资源管理
正确的资源管理可以防止内存泄漏并确保扩展的流畅性能。
问题
创建造型和可绘制对象而不清理会导致:
- 内存泄漏
- 性能下降
- 资源耗尽
- 渲染故障
解决方案:生命周期管理
监听项目事件
class MyExtension {
constructor(runtime) {
this.runtime = runtime;
this.customSkins = new Map();
this.customDrawables = new Map();
// 项目停止时清理
runtime.on('PROJECT_STOP_ALL', () => {
this.cleanup();
});
// 项目开始时清理(可选)
runtime.on('PROJECT_START', () => {
this.cleanup();
});
}
cleanup() {
const renderer = this.runtime.renderer;
// 首先销毁所有可绘制对象
for (const [name, drawableId] of this.customDrawables) {
renderer.destroyDrawable(drawableId, 'sprite');
}
this.customDrawables.clear();
// 然后销毁所有造型
for (const [name, skinId] of this.customSkins) {
renderer.destroySkin(skinId);
}
this.customSkins.clear();
}
}
最佳实践
1. 跟踪资源
使用 Map 或数组跟踪创建的资源:
constructor(runtime) {
this.skins = new Map(); // name -> skinId
this.drawables = new Map(); // name -> drawableId
}
2. 按顺序清理
始终按此顺序销毁:
- 先销毁可绘制对象(它们引用造型)
- 然后销毁造型(在没有可绘制对象使用它们之后)
cleanup() {
// 1. 销毁可绘制对象
for (const drawableId of this.drawables.values()) {
renderer.destroyDrawable(drawableId, 'foreground');
}
// 2. 销毁造型
for (const skinId of this.skins.values()) {
renderer.destroySkin(skinId);
}
}
3. 销毁前恢复
如果可绘制对象使用自定义造型,请在销毁自定义造型之前将其恢复为原始造型:
deleteSkin(skinName) {
const skinId = this.skins.get(skinName);
if (!skinId) return;
// 恢复使用此造型的所有目标
this._restoreTargetsFromSkin(skinId);
// 现在可以安全销毁
renderer.destroySkin(skinId);
this.skins.delete(skinName);
}
_restoreTargetsFromSkin(skinId) {
for (const target of this.runtime.targets) {
const drawableId = target.drawableID;
const currentSkin = renderer._allDrawables[drawableId].skin;
if (currentSkin._id === skinId) {
target.updateAllDrawableProperties();
}
}
}
4. 实现 dispose()
对于可以卸载的扩展:
dispose() {
// 清理所有资源
this.cleanup();
// 移除事件监听器
this.runtime.off('PROJECT_STOP_ALL', this.cleanup.bind(this));
// 清除引用
this.skins = null;
this.drawables = null;
}
常见模式
模式:对象池
重用可绘制对象而不是不断创建/销毁:
class OptimizedExtension {
constructor(runtime) {
this.drawablePool = [];
}
getDrawable() {
if (this.drawablePool.length > 0) {
return this.drawablePool.pop();
}
return renderer.createDrawable('foreground');
}
releaseDrawable(drawableId) {
// 重置为默认状态
renderer.updateDrawableProperties(drawableId, {
visible: false,
position: [0, 0, 0],
effects: { ghost: 0, brightness: 0, color: 0 }
});
// 返回池中
this.drawablePool.push(drawableId);
}
}