P5.js sketch gets slower even though i delete objects

Hi I made an object oriented sketch in p5.js that draws rectangles, that expands from the center.

Over time (a minute or two) the sketch slows down, even though I delete the rectangles that are no longer visible...

It seems like the framerate cannot go up, once it has gone down.

Does anybody have an explanaition or idea about how to approach such issue?

//Colors: Blue, Yellow, Red, Light Brown, Dark Brown
var colors = ['#04c8fc', '#e2c802', '#ff4f69', '#cd9479', '#96412d'];

var rects = [];
var howMany = 10;
var sz = 0;
var kill = false;
var j = 0;
var counter = 0;

function setup() {
  createCanvas(800, 500);   
  rectMode(CENTER);
  noStroke();
}

function draw() {
  background(colors[colors.length - 1]);

  for (var i = 0; i < rects.length; i++) {
    rects[i].display();

    if (kill) {
      //console.log("kill");
      rects.splice(0, 1); //Kills one element at index 0
      kill = false;
    }
  }

  if (frameCount == 1) {
    append(rects, new Pulse(sz, colors[counter % colors.length]));
    counter++;
  }
  if (frameCount % 25 == 0) {
    append(rects, new Pulse(sz, colors[counter % colors.length]));
    counter++;
  }
  console.log(rects.length);
  console.log(frameRate());
}

// Pulse class
function Pulse(_sz, _c) {
  this.sz = _sz;
  this.c = _c;

  this.display = function() {
    translate(width / 2, height / 2);
    rotate(radians(45));
    fill(this.c);
    rect(0, 0, this.sz, this.sz);
    resetMatrix();

    if (mouseX < width && mouseX >0 && mouseY < height && mouseY >0 ) {
      this.sz += map(mouseX, 0, width, -10, 10);
    } else {
      this.sz += 2;
    }

    if (abs(this.sz) > width * 1.8) {
      kill = true;
    }

  };
}
Tagged:

Answers

  • Over time (a minute or two) the sketch slows down, even though I delete the rectangles that are no longer visible...

    @Andreas_Ref - Do you really though? All the following does is remove a reference to the rectangle from the array:

    rects.splice(0, 1); //Kills one element at index 0

    This by no means guarantees the removal of the object itself - or child objects - via subsequent garbage collection...

    looks to me like the main problem is your display 'method': you've declared this as child function inside your object. You can get away with that if you're not instantiating many objects; but in this case - since you're creating an endless steam of objects - you've built yourself a nice little memory leak (or black hole). Check your task manager and the memory being eaten by your browser as the sketch runs (note also that console.log can contribute to this).

    I won't go into details but the solution is to add the 'method' to the object prototype:

    //Colors: Blue, Yellow, Red, Light Brown, Dark Brown
    var colors = ['#04c8fc', '#e2c802', '#ff4f69', '#cd9479', '#96412d'];
    
    var rects = [];
    var howMany = 10;
    var sz = 0;
    var kill = false;
    var j = 0;
    var counter = 0;
    
    function setup() {
      createCanvas(800, 500);   
      rectMode(CENTER);
      noStroke();
    }
    
    function draw() {
      background(colors[colors.length - 1]);
    
      for (var i = 0; i < rects.length; i++) {
        rects[i].display();
    
        if (kill) {
          //console.log("kill");
          rects.splice(0, 1); //Kills one element at index 0
          kill = false;
        }
      }
    
      if (frameCount == 1) {
        append(rects, new Pulse(sz, colors[counter % colors.length]));
        counter++;
      }
      if (frameCount % 25 == 0) {
        append(rects, new Pulse(sz, colors[counter % colors.length]));
        counter++;
      }
     // console.log(rects.length);
    //  console.log(frameRate());
    }
    
    // - - - - - - - - - - - - - - - //
    // Pulse class
    function Pulse(_sz, _c) {
      this.sz = _sz;
      this.c = _c;
    
    }
    
    Pulse.prototype.display = function() {
        translate(width / 2, height / 2);
        rotate(radians(45));
        fill(this.c);
        rect(0, 0, this.sz, this.sz);
        resetMatrix();
    
        if (mouseX < width && mouseX >0 && mouseY < height && mouseY >0 ) {
          this.sz += map(mouseX, 0, width, -10, 10);
        } else {
          this.sz += 2;
        }
    
        if (abs(this.sz) > width * 1.8) {
          kill = true;
        }
    
      };
    

    For a more detailed explanation read You don't know JS - this and object prototypes. In fact just read the whole series...

  • Thanks a lot blindfish, i'll give it another try :). And thanks for the reading reference as well!

  • I tried again with a non object oriented version (with help/inspiration from Jerome Herr), but the problem is the same...

    So shift() and splice() does not really remove the data I guess (only reference to it??)? How is it removed then?

    //Sketch still has performance issues and frameRate starts to drop after 1-2 minutes
    var howMany = 8;
    var frms = 30;
    
    var discs = [];
    var cols = [];
    
    var maxS = 0;
    var incr = 0;
    var diff = 0;
    
    var colors = ['#04c8fc', '#e2c802', '#ff4f69', '#cd9479', '#96412d'];
    
    function setup() {
      createCanvas(1280, 720);
      rectMode(CENTER);
      noStroke();
    
      maxS = width * 1.7;
      diff = maxS / howMany;
      incr = maxS / howMany / frms;
    
      for (var i = 0; i < howMany; i++) {
        var sz = map(i, 0, howMany, maxS, 0);
        append(discs, sz);
        append(cols, i % colors.length);
      }
    }
    
    function draw() {
      background(colors[colors.length - 1]);
    
      push();
      translate(width / 2, height / 2);
      rotate(radians(45));
    
      for (var i = 0; i < discs.length; i++) {
        if (discs[i] > maxS) {
          append(cols, (cols[(discs.length - 1)] + 1) % colors.length);
          cols.shift();
          discs.shift();
          append(discs, 0);
        }
        var sz = discs[i];
        fill(colors[cols[i]]);
        rect(0, 0, sz, sz);
        discs[i] += incr;
        //discs[i] += map(mouseX, 0, width, 0, 10);
    
      }
      pop();
      console.log(frameRate());
    }
    
  • @Andreas_Ref:

    note also that console.log can contribute to this...

    As in running console.log repeatedly (like every frame!) is a bad idea and might also be a factor in your problem. If you want to see the browser's framerate use your browser developer tools - e.g. instructions for Chrome can be found here.

  • @blindfish

    Sure, I know printing the frameRate isn't the best idea. The code is just provided to easily show how the frames drop over time (after 1-2 minutes).

    If I leave it out, the issue is the same though...

  • @Andreas_Ref: When I run your updated code (with console.log enabled or disabled) I'm not experiencing any noticeable fps slowdown and Chrome seems to be handling memory management well enough.

    So this could be a local issue: e.g. do you have a processor that throttles when under excessive load/temperatures? Note that with console.log running and the console open I do see significantly more processor activity in my Task Manager.

  • Hmm, weird... Have you tried to leave it on for 3-4 minutes? On my computer(s) it performs fine for the first period, but then it slows down...

  • OK: looks like different browsers behave differently. Chrome seems to cope and just keeps on running. Firefox (dev edition) consistently crashes: you can see it gradually eat up more and more memory then... 8-X

    Don't have time to look into the cause of the memory leak; but there's definitely one there; though not necessarily in your code.

  • Okay, thanks for looking into it... Strange stuff :/

Sign In or Register to comment.