2.x bug备忘录
一、spine和龙骨都存在内存泄漏
-
这个问题之前已经有人反馈了,但在2.4.11版本依旧没有处理: <原生平台spine造成的泄漏问题>
-
Creator 版本: 2.4.11
-
目标平台: iOS / Android / Win32 / 所有原生平台
-
重现方式:
1.先在空项目随便导入个spine动画资源用于测试
2.在原生devtools控制台输入以下代码用于测试
// 创建spine对象
function play(cd){
cc.assetManager.loadBundle('Dome',(err,bundle)=>{
bundle.load('domeSpine',sp.SkeletonData,(e,a)=>{
let newNode = new cc.Node()
window.playerSpine = newNode.addComponent(sp.Skeleton)
window.playerSpine.premultipliedAlpha = false
window.playerSpine.skeletonData = a;
window.playerSpine.setAnimationCacheMode(0);
window.playerSpine.setAnimation(0,'die',true);
window.playerSpine.getCurrent(0)
// 随便取dome spine上带有Attachment的slot
const slot = window.playerSpine.findSlot('wuqi')
// 泄漏点: getColor 返回的对象会泄漏
slot.getAttachment().getColor()
console.log('动作')//this.playerSpine.findSlot('wuqi').getAttachment().getColor() )
cd && cd()
})
})
}
// 清空spine数据强制垃圾回收
function clear(cd){
window.playerSpine && (window.playerSpine.skeletonData = null)
window.playerSpine && window.playerSpine.node.destroy()
window.playerSpine = null
cc.assetManager.getBundle('Dome').releaseAll();
cc.assetManager.removeBundle(cc.assetManager.getBundle('Dome'));
setTimeout(()=>{
window['forceGC']();
cd && cd()
})
}
// 循环创建/释放spine
function loop(){
play(()=>{
clear(()=>{
loop();
})
})
}
3.在控制台输入loop()开始测试泄漏
-
- 接着拍内存快照,打开Global handles查看在c++泄漏的对象 (距离为 - 的对象都是在C++加了引用计数的垃圾回收不了的对象)

然后发现349个color对象泄漏, 但这color对象的c++已经被释放了,访问到的数据是野指针的数据
- 接着拍内存快照,打开Global handles查看在c++泄漏的对象 (距离为 - 的对象都是在C++加了引用计数的垃圾回收不了的对象)
- 首个报错:
-
- 过一会触发断言 (项目引擎源码修改过这里原本显示断言 NativePtrToObjectMap::find(data) == NativePtrToObjectMap::end())

找到断言位置, 意思是data对象地址已经存在map容器里了,但看调用堆栈这data是NodeProxy对象刚构造出来的新地址,明显有内存泄漏
打开map容器看看到一堆已经释放的对象还在容器中, 触发断言原因就是这些已释放对象地址和新对象地址相同导致的
- 过一会触发断言 (项目引擎源码修改过这里原本显示断言 NativePtrToObjectMap::find(data) == NativePtrToObjectMap::end())
- 导致后果: 继续运行接着js报错
-
- 由于原生对象和js对象之间映射出了问题,导致new新对象可能返回的是已经释放的color对象

调用getAttachment返回的是color对象
,可见内存已经彻底放飞自我

最后因下面内存错误,导致动态申请内存失败闪崩(即使内存没用完)
false 意思应该是内存充足情况下分配内存错误
v8::ArrayBuffer::New is heap out of memory: false (no stack information)
- 由于原生对象和js对象之间映射出了问题,导致new新对象可能返回的是已经释放的color对象
- 之前哪个版本是正常的:creator3.8.1 没发现这些问题
- 重现概率: 99%
- 临时修复方案: 所有spine对象释放时都调用 _spineObjectDisposeCallback(ptr); 触发回收; 有性能问题


二、原生websocket泄漏
- Creator 版本: 2.4.11
- 目标平台: iOS / Android / Win32 / 所有原生平台
- 重现步骤: 正常创建websocket并关闭
let temp = new WebSocket('ws://xxxxxx');
setTimeout(()=>{
temp.close();
temp = null;
window['forceGC']()
}, 1000);
- 通过内存快照发现泄漏
- 导致泄漏原因: 黄色位置加一次引用计数后红色位置再次加引用计数, 初始化时总共加2个引用,释放时只减1个导致
- 修复方案: 注释掉其中一个