Forums > Javascript

text2d not being cleaned by javascript garbage collector

June 30, 2010 | 3:06 pm

Hi,

I have a script that creates new jit.gl.text2d objects and adds them to an array. When the array reaches a certain length, I want to remove the oldest item in the array. While I can remove the item from the array, the jit.gl.text2d object is not being deleted. I have tried slice, shift, setting a variable = to the object and then deleting the variable and setting it null. I have done this aftef setting the text of the jit.gl.text to null. No matter what it doesn’t get deleted and eventually the script crashes Max. Any suggestions or pointers on removing objects in javascript (I have searched the web but everything seems to indicate that slicing the array should do it)? Thanks

code:
‘ autowatch = 1;
inlets = 1;
outlets = 1;
var i = -1;
var textColor = 0.5;
var textLineArray = new Array();
var deadText=null;

function textLineMaker(a){
post("textLineArray length is " + textLineArray.length +"n");
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////tests array length and removes oldest item. < ------leak is here?
if(textLineArray.length>10){
post("delete calledn");
deadText = textLineArray.shift();
deadText = null;
post("deadText is " + deadText + "n");
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////Sets texts variables
var xMultiplier = Math.sin(Math.random()*360);
if (xMultiplier < 0){
xMultiplier = -0.5;
} else {
xMultiplier = 0.5;
}
var yMultiplier = Math.sin(Math.random()*360);
if (yMultiplier < 0){
yMultiplier = -1;
} else {
yMultiplier = 1;
}
var xPosition = Math.random()*xMultiplier;
var yPosition = Math.random()*yMultiplier;
var zPosition = 0.0;
textColor = (Math.floor(Math.random()*125+50))/256;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// creates the jitterObject
textLineArray.push(new JitterObject("jit.gl.text2d", "werds"));
textLineArray[textLineArray.length-1].antialias = 1;
textLineArray[textLineArray.length-1].align = 1;
textLineArray[textLineArray.length-1].color = [textColor,textColor,textColor,1.];
textLineArray[textLineArray.length-1].position = [xPosition,yPosition,zPosition];
//textLineArray[iterator].rotate = 90;
textLineArray[textLineArray.length-1].font("Arial");
var textSize = Math.floor(Math.random()*10)+4;
textLineArray[textLineArray.length-1].size(textSize);
textLineArray[textLineArray.length-1].face("bold");
textLineArray[textLineArray.length-1].tracking = 1;
textLineArray[textLineArray.length-1].screenmode = 1;
textLineArray[textLineArray.length-1].depth_enable = 0;
textLineArray[textLineArray.length-1].text(a);
textLineArray[textLineArray.length-1].draw();
}


June 30, 2010 | 4:12 pm

You cannot know in JS when it will do garbage collection. If you need to call it,

try calling

gc();

in your script at the appropriate point.

Cheers

-A


July 1, 2010 | 3:48 am

thanks for the suggestion but it doesn’t seem to work. I would think that shifting the array to a variable and then resetting the variable would remove all references to the object freeing it up for removal, but it just doesn’t happen. Something must be referencing the text2d object still, but for the life of me I don’t know what.


July 1, 2010 | 9:53 am

Hello maxers,

@ Andrew Pask : didn’t know about gc ( ) ; thanks.

@ pcm ; example :

– Pasted Max Patch, click to expand. –

autowatch = 1 ;

var text = [ ] ;

var myrender = new JitterObject ("jit.gl.render", "toto") ;
myrender.erase_color = [0., 0., 0., 1.] ;
myrender.blend_enable = 1 ;
myrender.depth_enable = 0 ;
myrender.ortho = 0 ;

function ajouter (a)
{
var blabla = new JitterObject("jit.gl.text2d", "toto") ;
blabla.color = [Math.random ( ), Math.random ( ), Math.random ( ), Math.random ( )] ;
blabla.position = [Math.random ( ) - 0.5, Math.random ( ) - 0.5, 0.] ;
blabla.blend_enable = 1 ;
blabla.depth_enable = 0 ;
blabla.font ("Arial") ;
blabla.size (48) ;
blabla.text (a) ;

if (text.length > 2)
{
text.splice (0, text.length) ;
gc ( ) ;
}

text.push (blabla) ;

myrender.erase ( ) ;
myrender.drawswap ( ) ;
}

function clear ( )
{
text.splice (0, text.length) ;
gc ( ) ;

myrender.erase ( ) ;
myrender.drawswap ( ) ;
}

HTH.

Attachments:
  1. vinaigrette.zip

July 1, 2010 | 6:35 pm

HTH,

Thanks so much for the help. Your script is far more elegant than mine. Unfortunately, it still crashes Max. I have modified the patch you built to allow dumping a massive amount of text into the script. I also changed the script to just cut the oldest text once it reaches the correct length. On my machine it runs for about 15-20 minutes before crashing max. I am attaching a zip with the changes. Thanks for your help.

pcmxa

Attachments:
  1. MemLeak.zip

July 1, 2010 | 9:40 pm

ok, we think there might be some kind of leak here. The text2d object is getting GCd ok, but there is some other leak.

In the meantime, we’d suggest a workaround to use one jit.gl.text2d object @automatic 0, which walks an array, changes the positions, colors and text and renders the text explicitly like the following:

// to add to the text array:

var newline = new Object();
newline.str = thestring;
newline.color = [Math.random ( ), Math.random ( ), Math.random ( ), Math.random ( )];
newline.position = [Math.random ( ) - 0.5, Math.random ( ) - 0.5, 0.] ;
text.push(newline);

// to draw:

for (i=0; i
text2dobj.text(text[i].str);
text2dobj.color = text[i].color;
text2dobj.position = text[i].position;
text2dobj.draw();
}

Thanks for the report

-A


July 2, 2010 | 12:37 pm

Hello maxers,

Andrew’s suggestion way :

– Pasted Max Patch, click to expand. –

autowatch = 1 ;

var page = [ ] ;
var index = 0 ;

var myrender = new JitterObject ("jit.gl.render", "toto") ;
myrender.erase_color = [0., 0., 0., 1.] ;
myrender.blend_enable = 1 ;
myrender.depth_enable = 0 ;
myrender.init = 0 ;

var blabla = new JitterObject ("jit.gl.text2d", "toto") ;
blabla.blend_enable = 1 ;
blabla.depth_enable = 0 ;
blabla.automatic = 0 ;
blabla.font("Arial") ;
blabla.size(48) ;

function ajouter (a)
{
var i ;
var word = {
color : [Math.random ( ), Math.random ( ), Math.random ( ), Math.random ( )],
position : [Math.random ( ) - 0.5, Math.random ( ) - 0.5, 0.],
str : a
} ;

page[index] = word ;

if (index < 3)
{
index ++ ;
}
else
{
index = 0 ;
}

if (!myrender.init) // ########### ???
{
myrender.drawswap () ;
myrender.init = 1 ;
}

myrender.erase ( ) ;

for (i = 0 ; i < page.length ; i++)
{
blabla.position = page[i].position ;
blabla.color = page[i].color ;
blabla.text (page[i].str) ;
blabla.draw ( ) ;
}

myrender.drawswap ( ) ;
}

!
!
!
!

Two questions :

- why do i have to "init" for rendering first item ?
- why do i have an error "jit.gl.render : couldn’t make OpenGL on pwindow toto" when i close the patch ?

Thanks.


July 9, 2010 | 10:21 pm

Thanks, that works great for that part of the patcher. the trouble is I need to also have two other groups of text2d objects animating. One takes a line of text it is fed and moves it from the middle of the screen to the bottom. The other takes a number of lines all at once and moves them up to the top. To do this I built arrays to hold the text2d objects and then scripted their movement. This got around making new or deleting old text2d objects. There are always the same amount (the original ones) that are animated. I thought this would get around the memory leak but it hasn’t seemed to. I am still getting max crashes stating max crashed due to java low memory. I am also zipping the relevant files below (not patcher yet I need to simplify this huge one I am working with) but here is the script that takes single lines and moves them to the bottom and then unloads each one by one after a certain number are loaded. If anyone can point out where the leak is or how to adopt Andrew’s suggestion, I would be exstatic.

autowatch = 1;
            inlets = 1;
            outlets = 2;

           ////set the maximum number of lines and initial conditions

            var textLine = "Hello";
            var i = -1;
            var line = 0;
            var numberOfLines = 18;
            var maxLines = 19;
            var moveAmount = 0.005;
            var minHeight = -0.75

            ////build array of text2d objects

            var textLineArray = new Array();
            for (j=0;j<20;j++){
                textLineArray[j]= new JitterObject("jit.gl.text2d","werds");
                    textLineArray[j].text();
                    textLineArray[j].antialias = 1;
                    textLineArray[j].align = 1;
                    textLineArray[j].color = [0.,0.,0.,0.];
                    textLineArray[j].position = [0.,0.,0.];
                    textLineArray[j].size(14);
                    textLineArray[j].face("bold");
                    textLineArray[j].tracking = 1.2;
                    textLineArray[j].screenmode = 1;
                    textLineArray[j].blending_enable = 1;
                }

            ////create timers and intervals

            var loadIntervalIDArch= new Task(loadText, this);
            loadIntervalIDArch.interval = 20;

            var unloadIntervalIDArch= new Task(unloadText, this);
            unloadIntervalIDArch.interval = 20;

            ////set the number of objects to be used in the animation

           function poemLengthSetter(length){
                numberOfLines=length;
            }

             ////clear any text in any of the aobjects in the array and reset conditions

            function removeText(){
                     for (k=0;knumberOfLines){
                    //    return;
                   // }

                    ////set the argument received from a text file to a global variable
                    ////and set the proerties and text of the corresponding text2d object in the array
                    textLine = a;
                    textLineArray[i].color = [1.,1.,1.,1.];
                    textLineArray[i].position = [0.,0.,0.];
                    textLineArray[i].font("Arial");
                    textLineArray[i].size(14);
                    if (i==0){
                        textLineArray[i].size(20);
                    }

                    ////draw the text and call the loading function
                    textLineArray[i].text(textLine);
                    textLineArray[i].draw();
                    lineMover();
            }

            ////functions that load the timers to move the text
            function lineMover(){
                    loadIntervalIDArch.repeat();
            }

            function lineUnloader(){
                    unloadIntervalIDArch.repeat();
            }

///////function that moves the text and fades in the color

function loadText(){

    /////cancel the unload timer if it is still going

    unloadIntervalIDArch.cancel();
     //post("loadTextArchive called");

    /////check to see if the text is above it bottom position, if so
    /////move the text and lighten an incement
     if (textLineArray[line].position[1] >= minHeight){
        //post("move called");
        var i = textLineArray[line].position[1];
        var c = textLineArray[line].color[0];
        i -= moveAmount;
        c= textLineArray[line].position[1]/minHeight;

        /////set the maximum color level

        if (c>=0.7){
            c=0.7;
        }
        //post(c);

        ////set the position and color

        textLineArray[line].position = [0.0,i, 0.0];
        textLineArray[line].color= [c,c,c,1.];
        //post("movedn");
    }

    ////if text has reached minum height set new minimum height and increment the line number
    ////also cancel the movement timer

    if (textLineArray[line].position[1] < = minHeight){
        minHeight += .033;
        line += 1;
        loadIntervalIDArch.cancel();
        //post("mined out heightn");
    }  

    ////if the maximum number of input lines has ben reached
    ////cancel the timer and reset variables to initial conditions
    ////call the unload timer and send out as bang to dump the accumulated lines

    if (line >= numberOfLines){
        loadIntervalIDArch.cancel();
        minHeight = -0.75;
        line = 0;
        //post(line);
        lineUnloader();;
        outlet(0,"bang");
    }
}
    ////unloads the text.  is exctly opposite from loading text

function unloadText(){
     loadIntervalIDArch.cancel();
    //post(line + "n")
     //post("unloadTextArchive calledn");

 //// if the text2d object is not off the screen move it down and fade it out

     if (textLineArray[line].position[1] >= -1.){
        //post("move called");
        var i = textLineArray[line].position[1];
        var c = textLineArray[line].color[0];
        i -= moveAmount;
        c-=(1-(line*0.025))/40;
        if (c< =0){
            c=0;
        }
        //post(c);
        textLineArray[line].position = [0.0,i, 0.0];
        textLineArray[line].color= [c,c,c,1.];
        //post("movedn");
    }

 ////if the linehas reached the bottom increment the line to move the next text2d object down

    if (textLineArray[line].position[1] <= -1.){
        line += 1;
        //post("maxed out heightn");
    }  

////if the last line has been reached, kill the timer
//// and reset the initial conditions
///also run the remove text function to erase the text prpertiesof the text2d object
////finally issue a bang out the right outlet to begin the process of loadin a new poem
    if (line >= numberOfLines){
        unloadIntervalIDArch.cancel();
        post("unload cancled");
       minHeight = -0.75;
        line = 0;
        //post(line);
        removeText();
        outlet(1,"bang");
    }
}
Attachments:
  1. js_files.zip

Viewing 8 posts - 1 through 8 (of 8 total)