有没有办法检查一个对象是否真的被释放了?
Is there a way to check if an object is really released?
根据 doc、destroy()
方法
Destroys this Game Object removing it from the Display List and Update
List and severing all ties to parent resources.
Also removes itself from the Input Manager and Physics Manager if
previously enabled.
Use this to remove a Game Object from your game if you don't ever plan
to use it again. As long as no reference to it exists within your own
code it should become free for garbage collection by the browser.
If you just want to temporarily disable an object then look at using
the Game Object Pool instead of destroying it, as destroyed objects
cannot be resurrected.
我写这段代码是为了检查一个对象是否真的被释放了
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);
<script src="https://cdn.jsdelivr.net/npm/phaser@3.55.2/dist/phaser.js"></script>
发现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
还留在那里
我现在在一个答案中回答,因为我将不得不讨论一些细节。
你的代码几乎是 100% 正确的,只需要删除所有指向对象的引用(variable/properties),在本例中为:delete this.bullet
.
Just in case: delete
is a javascript operator https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete
请记住,FinalizationRegistry
只会通知您,当浏览器决定“垃圾收集”该对象时,这可能需要一段时间 (在极少数情况下对象甚至可以一直保留到浏览器关闭).
Important: As mention on the mdn documentation:
'...Note: Cleanup callbacks should not be used for essential program logic. ...`. And you don't really have to worry about correct destory/disposed objects, it's the browsers job, to garbage collect them if it needs more space or so.
如果你想测试,如果它有效,你需要填充内存,并“强制”浏览器开始垃圾收集。此页面上有一个很好的示例:https://www.javascripture.com/FinalizationRegistry 说明如何完成。
我改编了上面 link 中的示例,对于您的示例,您可以在此处查看实际效果:
Warning: this can take some seconds, 115s in my last run. The filling up of the memory with objects, should not be use in production, since it needlessly would slow/strain the computer/browser/application.
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;
});
<script src="https://cdn.jsdelivr.net/npm/phaser@3.55.2/dist/phaser.js"></script>
根据 doc、destroy()
方法
Destroys this Game Object removing it from the Display List and Update List and severing all ties to parent resources.
Also removes itself from the Input Manager and Physics Manager if previously enabled.
Use this to remove a Game Object from your game if you don't ever plan to use it again. As long as no reference to it exists within your own code it should become free for garbage collection by the browser.
If you just want to temporarily disable an object then look at using the Game Object Pool instead of destroying it, as destroyed objects cannot be resurrected.
我写这段代码是为了检查一个对象是否真的被释放了
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);
<script src="https://cdn.jsdelivr.net/npm/phaser@3.55.2/dist/phaser.js"></script>
发现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
还留在那里
我现在在一个答案中回答,因为我将不得不讨论一些细节。
你的代码几乎是 100% 正确的,只需要删除所有指向对象的引用(variable/properties),在本例中为:delete this.bullet
.
Just in case:
delete
is a javascript operator https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete
请记住,FinalizationRegistry
只会通知您,当浏览器决定“垃圾收集”该对象时,这可能需要一段时间 (在极少数情况下对象甚至可以一直保留到浏览器关闭).
Important: As mention on the mdn documentation: '...Note: Cleanup callbacks should not be used for essential program logic. ...`. And you don't really have to worry about correct destory/disposed objects, it's the browsers job, to garbage collect them if it needs more space or so.
如果你想测试,如果它有效,你需要填充内存,并“强制”浏览器开始垃圾收集。此页面上有一个很好的示例:https://www.javascripture.com/FinalizationRegistry 说明如何完成。
我改编了上面 link 中的示例,对于您的示例,您可以在此处查看实际效果:
Warning: this can take some seconds, 115s in my last run. The filling up of the memory with objects, should not be use in production, since it needlessly would slow/strain the computer/browser/application.
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;
});
<script src="https://cdn.jsdelivr.net/npm/phaser@3.55.2/dist/phaser.js"></script>