【问题标题】:Is there a way to check if an object is really released?有没有办法检查一个对象是否真的被释放了?
【发布时间】:2022-01-26 14:26:37
【问题描述】:

根据docdestroy() 方法

销毁此游戏对象,将其从显示列表中移除并更新 列出并切断与父资源的所有联系。

也会从输入管理器和物理管理器中移除自身,如果 之前启用。

如果您从未计划过,请使用它从游戏中移除游戏对象 再次使用它。只要在您自己的内部不存在对它的引用 它应该可以免费用于浏览器的垃圾收集。

如果你只是想暂时禁用一个对象,那么看看使用 游戏对象池而不是销毁它,作为被销毁的对象 无法复活。

我写这段代码是为了检查一个对象是否真的被释放了

class BootScene extends Phaser.Scene {
  constructor() {
    super({ key: 'BootScene' });
  }
  create() {
    this.bullet = this.add.circle(50, 50, 10, 0xff0000);
    this.physics.add.existing(this.bullet);
    this.bullet.body.setVelocity(150, 0);

    this.slow_delta = 0;

    this.bullet.body.setCollideWorldBounds(true);
    this.bullet.body.onWorldBounds = true;
    this.bullet.key = 'enemy'
    this.bullet.body.world.on('worldbounds', () => {
      console.log('destroy')
      this.bullet.destroy();
    })
  }

  update(time, delta) {
    // examine the t value every 100 ms
    this.slow_delta += delta;
    if (this.slow_delta > 1000 && time < 100000) {
      this.slow_delta = 0;
      console.log(time, this.bullet.x);
    }
  }
}

var config = {
  width: 800,
  height: 500,
  physics: {
    default: 'arcade',
    arcade: {
      gravity: { y: 0 },
    }
  },
  scene: [BootScene]
}

var game = new Phaser.Game(config);
&lt;script src="https://cdn.jsdelivr.net/npm/phaser@3.55.2/dist/phaser.js"&gt;&lt;/script&gt;

bullet离开世界后发现,它的位置停留在790

但是,update() 仍然可以获取其位置,而不是 undefined,这似乎意味着该对象实际上并未被释放。

有没有办法检查一个对象是否真的被释放了?

在@winner_joiner的提醒下,我也试过这段代码

const cleanup = new FinalizationRegistry(key => {
});
this.bullet.body.world.on('worldbounds', () => {
  console.log('destroy')
  this.bullet.destroy();
  cleanup.register(this.bullet, 'werwer');
})

bullet 仍然留在那里。

【问题讨论】:

标签: javascript phaser-framework


【解决方案1】:

我现在在一个答案中回答,因为我必须深入一些细节。

好吧,您的代码几乎 100% 正确,只需删除指向对象的所有引用(变量/属性),在本例中为:delete this.bullet

以防万一:delete是一个javascript操作符https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete

请记住,FinalizationRegistry 只会通知您,当浏览器决定“垃圾收集”对象时,这可能需要一段时间 (在极少数情况下,对象甚至可能会一直停留到浏览器已关闭).

重要提示:mdn documentation 中提到: '...注意:清理回调不应用于基本程序逻辑。 ...`。而且您不必担心正确的销毁/处置对象,这是浏览器的工作,如果需要更多空间左右来垃圾收集它们。

如果你想测试,如果它有效,你需要填充内存,并“强制”浏览器开始垃圾收集。在这个页面上有一个很好的例子:https://www.javascripture.com/FinalizationRegistry 说明了它是如何完成的。

我根据上面的链接改编了这个例子,作为你的例子,你可以在这里看到它的实际效果:

警告:这可能需要几秒钟,在我上次运行时需要 115 秒。用对象填充内存,不应在生产中使用,因为它会不必要地减慢/拖累计算机/浏览器/应用程序。

class BootScene extends Phaser.Scene {
  constructor() {
    super({ key: 'BootScene' });
  }
  create() {
    this.bullet = this.add.circle(50, 50, 10, 0xff0000);
    this.physics.add.existing(this.bullet);
    this.bullet.body.setVelocity(150, 0);

    this.slow_delta = 0;

    this.bullet.body.setCollideWorldBounds(true);
    this.bullet.body.onWorldBounds = true;
    this.bullet.key = 'enemy'
    
    // register object to watch
    registry.register(this.bullet, 42);
    
    this.bullet.body.world.on('worldbounds', async () => {
      console.log('destroy');
      this.bullet.destroy();
      
      // Remove the last reference to the bullet object
      delete this.bullet;

      // START -- THIS part should not be used for production
      const startTime = Date.now();
      console.log('Allocating a lot of objects to try to force garbage collection');
      while (waitingForCleanup) {
        for (let i = 0; i < 1000; i++) {
          const x = new Array(100);
        }
        await sleep(10);
      }
      console.log(` the bullet was reclaimed after ${((Date.now() - startTime) / 1000).toFixed(1)}s`);
      // END -- THIS part should not be used for production

    })
  }

  update(time, delta) {
    // examine the t value every 100 ms
    this.slow_delta += delta;
    if (this.slow_delta > 1000 && time < 100000) {
      this.slow_delta = 0;
      //console.log(time, this.bullet.x);
    }
  }
}

var config = {
  width: 800,
  height: 500,
  physics: {
    default: 'arcade',
    arcade: {
      gravity: { y: 0 },
    }
  },
  scene: [BootScene]
}

var game = new Phaser.Game(config);

const sleep = (ms) => new Promise(r => setTimeout(r, ms));

let waitingForCleanup = true;
const registry = new FinalizationRegistry((heldValue) => {
  console.log(`cleanup: ${heldValue}`);
  waitingForCleanup = false;
});
&lt;script src="https://cdn.jsdelivr.net/npm/phaser@3.55.2/dist/phaser.js"&gt;&lt;/script&gt;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-16
    • 1970-01-01
    • 2010-11-20
    • 2021-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多