Creator2.x 引擎原生端内存泄漏崩溃BUG (骨骼动画、websocket)

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++加了引用计数的垃圾回收不了的对象)
      image
      然后发现349个color对象泄漏, 但这color对象的c++已经被释放了,访问到的数据是野指针的数据
      image
  • 首个报错:
    • 过一会触发断言 (项目引擎源码修改过这里原本显示断言 NativePtrToObjectMap::find(data) == NativePtrToObjectMap::end())
      X6kMGPmJmn
      找到断言位置, 意思是data对象地址已经存在map容器里了,但看调用堆栈这data是NodeProxy对象刚构造出来的新地址,明显有内存泄漏JG6TYQKeK9
      打开map容器看看到一堆已经释放的对象还在容器中, 触发断言原因就是这些已释放对象地址和新对象地址相同导致的
      KZNlXfwhem
  • 导致后果: 继续运行接着js报错
    • 由于原生对象和js对象之间映射出了问题,导致new新对象可能返回的是已经释放的color对象
      njHFlzbE8P
      调用getAttachment返回的是color对象 :sweat_smile:,可见内存已经彻底放飞自我
      image
      最后因下面内存错误,导致动态申请内存失败闪崩(即使内存没用完)
      false 意思应该是内存充足情况下分配内存错误
      v8::ArrayBuffer::New is heap out of memory: false (no stack information)
      image
  • 之前哪个版本是正常的:creator3.8.1 没发现这些问题
  • 重现概率: 99%
  • 临时修复方案: 所有spine对象释放时都调用 _spineObjectDisposeCallback(ptr); 触发回收; 有性能问题
    image
    image
    image

二、原生websocket泄漏

  • Creator 版本: 2.4.11
  • 目标平台: iOS / Android / Win32 / 所有原生平台
  • 重现步骤: 正常创建websocket并关闭
let temp = new WebSocket('ws://xxxxxx');
setTimeout(()=>{ 
  temp.close(); 
  temp = null; 
  window['forceGC']()
}, 1000);

  • 通过内存快照发现泄漏
    img_v3_026a_214ecdef-2e23-4d64-ae95-5bcafb75e2fg
  • 导致泄漏原因: 黄色位置加一次引用计数后红色位置再次加引用计数, 初始化时总共加2个引用,释放时只减1个导致
    img_v3_026a_7eebdf69-7e1d-495b-ab18-dbedb24a630g
  • 修复方案: 注释掉其中一个
    img_v3_026a_0e1de6a4-6bae-43f3-91ca-f31314f9b56g
4赞

@minggo @dumganhar 这个看看修一下不

WebSocket 的改动,我看是在


中引入的。
之前应该是有 PR 中描述的原因的,但可能没有考虑周全,导致可能的泄露问题。我们会排查一下。

WebSocket 问题,先建一个 issue:


后续我查下。

@jordiwang




2.4.13有修复过内存泄漏问题,烦请验证下,我用2.4.13未能复现