最近在改Away3D源码的时候遇到个很郁闷的问题,发现创建的Mesh 释放不掉。
分析源码发现 EntityListItemPool 类中逻辑Bug在getItem()函数中发现_poolSize 对象池大小如果够用的情况下 它采用的方式是复用EntityListItem
那么假设我删除了场景上有10个对象我全部删除了然后我再创建9个 这时候总有1个对象是被缓存着的。一直要等到我创建第10个对象他才会被释放掉。
没辙了跑到 看看对象销毁流程吧。
对象被销毁时会调用 Scene3D 的 unregisterEntity函数,这个函数只是删除了Scene3D 和 显示对象的引用。但是EntityListItemPool中还是存在实例引用
看了看收集器 每次都要经过 Scene3D 的 traversePartitions函数。
那我先在unregisterEntity函数调用的时候做一次记录把要删除的显示对象添加到一个列表中。
private var _unregisterEntityList:Vector.<Entity> = new Vector.<Entity>;
/**
* When an entity is removed from the scene, or from one of its children, remove it from its former partition tree.
* @private
*/
arcane function unregisterEntity(entity : Entity) : void
{
_unregisterEntityList.push(entity);
entity.implicitPartition.removeEntity(entity);
}
这样在下一帧执行渲染的时候我就知道要释放掉哪些对象了。然后修改traversePartitions函数.
public function traversePartitions(traverser : PartitionTraverser) : void
{
var i : uint;
var len : uint = _partitions.length;
if(traverser is EntityCollector)
{
while(_unregisterEntityList.length)
{
var _entity:Entity = _unregisterEntityList.shift();
(traverser as EntityCollector).entityListItemPool.unmap(_entity);
(traverser as EntityCollector).renderableListItemPool.unmap(_entity);
}
}
traverser.scene = this;
while (i < len)
_partitions[i++].traverse(traverser);
}
每次在新的一轮收集前把上一帧要清楚掉的对象全部干掉。
然后跑到entityListItemPool 类里添加一段代码:
public function unmap(mesh:Entity) : void
{
var _mesh:Mesh = mesh as Mesh;
for(var j:int =0;j<_mesh.numSubMesh;j++)
{
for(var i:int = 0; i < _pool.length; i++)
{
if((_pool[i].renderable is SubMesh) && (_pool[i].renderable as SubMesh).parentMesh && (_pool[i].renderable as SubMesh).parentMesh == _mesh)
{
(_pool[i].renderable as SubMesh).parentMesh = null;
_pool.splice(i,1);
_poolSize --;
continue;
}
}
}
}
这样保证了对象的释放。OK 这下好了
测试下了一下没有问题全部乖乖的垃圾回收了。
Away3D 的实体收集器Bug