Skip to content

Redrawing tiles seems to cause memory leak (PIXI 8) #169

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
ChemistryGull opened this issue Dec 29, 2024 · 3 comments
Open

Redrawing tiles seems to cause memory leak (PIXI 8) #169

ChemistryGull opened this issue Dec 29, 2024 · 3 comments

Comments

@ChemistryGull
Copy link

Redrawing the tilemap this way (see code below) causes an exponential increase in memory usage, in the first minute unnoticeable but spiking till failure after about 2 minutes when running at 60 FPS. Neither tilemap.clear() nor tilemap.removeChildren() prevents this from happening, some data seems to not be cleared while continuing to build up. What would be the 'correct' way of clearing the tilemap in order to redraw it?

Using the latest release of tilemap (v5.0.1)

import * as PIXI from "pixi.js";
import { CompositeTilemap } from '@pixi/tilemap';

const app = new PIXI.Application();
const tilemap = new CompositeTilemap();
const playerContainer = new PIXI.Container();

(async () => {

  await app.init({
    background: "#999999",
    width: 800,
    height: 600,
    resizeTo: window,
  });
  app.canvas.style.position = "absolute"
  document.body.appendChild(app.canvas);
  app.stage.addChild(playerContainer);


  await PIXI.Assets.add({ alias: 'atlas', src: 'assets/atlas.json' });
  await PIXI.Assets.load(['atlas']);

  app.stage.addChild(tilemap);

  app.ticker.add(main)
})();


function main() {

  tilemap.clear();
  tilemap.removeChildren();

  for (var c = 0; c < world.loadedChunks.length; c++) {
    
    var chunk = world.chunkMap[world.loadedChunks[c]];

    for (var y = 0; y < S.chunkSize; y++) {
      for (var x = 0; x < S.chunkSize; x++) {
        var tile = chunk.tile[y * S.chunkSize + x];


        tilemap.tile(tileTextures[tile][3], x * S.tw + chunk.x * S.chunkSize * S.tw + viewport.x, y * S.th + chunk.y * S.chunkSize * S.th + viewport.y);

      }
    }
  }
}
@ivanpopelyshev
Copy link
Collaborator

Looks like a bug, but where...

@ChemistryGull
Copy link
Author

Curious too. I created a small Test project eliminating as much of my code as possible. It just draws 100x100 tiles of grass 60 times per second. 100x100 to see the memory leaking effect in a reasonable time (usually around 1-3 minutes), it behaves the same with fewer tiles, it just takes longer.

The main_test.js looks like this:

import * as PIXI from "pixi.js";
import { CompositeTilemap } from '@pixi/tilemap';

const app = new PIXI.Application();
const tilemap = new CompositeTilemap();

(async () => {

  await app.init({
    background: "#999999",
    width: 800,
    height: 600,
    resizeTo: window,
  });

  app.canvas.style.position = "absolute"
  document.body.appendChild(app.canvas);

  // --- Load tilemaps

  await PIXI.Assets.add({ alias: 'atlas', src: 'assets/atlas.json' });
  await PIXI.Assets.load(['atlas']);

  app.stage.addChild(tilemap);

  main();

})();

function main(param) {
  console.log("running main loop");
  
  tilemap.clear(); 
  tilemap.removeChildren();

  for (var y = 0; y < 100; y++) {
    for (var x = 0; x < 100; x++) {
      
      tilemap.tile("grass", x * 32, y * 32 );

    }
  }
  requestAnimationFrame(main)
}

I have built and attached that project in case you want to test it. It should run on a a simple python http server or similar.:
Test Project dist.zip
(In case you run it watch out for your ram usage and close the browser window before the computer crashes)

So yeah it seems like tilemap.clear() or tilemap.removeChildren() don't remove everything (Although I am not totally sure if thats their job and there is another way to clear the tilemap that i am missing).

@ChemistryGull
Copy link
Author

Some additional information:

  • The leaked RAM is not freed once you close the application. It just builds up and only restarting the PC frees the RAM again. (This is different to when I, for example, push Objects into an array, where when you close the application the RAM space is freed again).
    See the following Image on what this looks like: After starting the loop, for some time memory usage is stable, then it starts to increase pretty fast. The Application is stopped, the memory usage remains high. Closing Chrome does not reduce memory usage. Which is strange.
    Memory

  • Creating a entirely new CompositeTilemap each loop and deleting the previous one (app.stage.removeChildAt(0) to avoid buildup) does not solve this issue. Normally, the tilemap should be deleted from memory when it goes out of scope if I'm not mistaken. And the tilemap added to app.stage is cleared via app.stage.removeChildAt(0). However, somewhere there is still data building up.

  • My guess would be that CompositeTilemap() stores data somewhere else too? Possibly the frames are sent to a renderbuffer/framebuffer and then not cleared properly?

import * as PIXI from "pixi.js";
import { CompositeTilemap } from '@pixi/tilemap';

const app = new PIXI.Application();

(async () => {

  await app.init({
    background: "#999999",
    width: 800,
    height: 600,
    resizeTo: window,
  });

  app.canvas.style.position = "absolute"
  document.body.appendChild(app.canvas);

  // --- dummy rectangle that gets removed in loop. 
  const rectangle = new PIXI.Graphics()
      .rect(200, 200, 100, 150)
      .fill({
        color: 0xff0000,
      })
  app.stage.addChild(rectangle);

  // --- Load tilemaps

  await PIXI.Assets.add({ alias: 'atlas', src: 'assets/atlas.json' });
  await PIXI.Assets.load(['atlas']);

  main();

})();

function main(param) {
  console.log("running main loop");

  app.stage.removeChildAt(0);

  var tilemap = new CompositeTilemap();
  app.stage.addChild(tilemap);

  for (var y = 0; y < 100; y++) {
    for (var x = 0; x < 100; x++) {
      
      tilemap.tile("grass", x * 32, y * 32 );

    }
  }

  requestAnimationFrame(main)
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants