已阅读相关贴
Google Play后台崩溃日志 - Creator - Cocos中文社区
cocos creator 2.0.6 版本在安卓中退出后再重新进入游戏时崩溃 - Creator - Cocos中文社区
我们项目(单机未使用热更新)从bugly上捕获了一批Android 的NDK崩溃,崩溃次数并不多,堆栈PC地址分析后的调用栈
v8::HandleScope::Initialize(v8::Isolate*)
:?
AutoHandleScope
js-bindings/jswrapper/v8/ScriptEngine.hpp:65
se::ScriptEngine::init()
js-bindings/jswrapper/v8/ScriptEngine.cpp:379
se::ScriptEngine::start()
js-bindings/jswrapper/v8/ScriptEngine.cpp:570
AppDelegate::applicationDidFinishLaunching()
AppDelegate.cpp:65
Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit
android/jni/JniImp.cpp:197
明显这是引擎启动发生了crash,简单分析多条记录后发现,触发crash的用户使用时长从1分钟到数小时不等。
也就是说,这是第二次调用初始化。
在App未关闭,什么情况会导致二次调用引擎初始化,以下是我对这个问题的分析
Android的Activity的生命周期内,如弹出一个前台AdActivity,则CocosActivity进入后台,发生内存不足时,系统就会清理后台Activity,对应的GLsurfaceview也自然跟着被删除,GLSurfaceView清理后,系统也会自动处理GLSurfaceView对应的EGLContext内存,如opengl里面的各种BufferData、Texture、framebuffer等资源都会一并清理, 但这个清理不会去清除NDK/JNI部分! 引擎原生c++部分的内存和V8依然还在。
AdActivity关闭退回游戏Act,CocosActivity重建,这时执行过程就是上面的crash堆栈表。
由于se::ScriptEngine是单例,在第一次的CocosActivity创建时就已经被创建,所以二次Act重建不会创建新的ScriptEngine实例,但这里涉及到了v8的一个知识点。
使用v8创建可执行的js runtime有以下过程,创建v8::platform-> 创建v8::Isolate -> 创建v8::Context -> 执行jsb注册-> 运行js
一次App进程内只需创建一次 v8::platform即可, 但v8::Isolate不同,这个对象和线程是绑定的,不同线程不能混用v8::Isolate,使用就崩(可以新建一个thread测试),创建了本线程的Isolate,则后续js 运行环境以及jsb绑定才能可用,AutoHandleScope才能正常调用。
基于上述知识点,我们完全可以在一个cocos程序里面创建2个完全独立不干扰的js runtime环境(本人亲测)
android 上cocos主进程和v8的主进程是靠GlSurfaceView内部的GLThread驱动。
,这意味着,不同的GLSurefaceView不能共享:Isolate,也就是不能共用 ScriptEngine实例。
问题解决思路,在CocosActivity被销毁(不管是主动退出还是系统清理)后,都该主动去destroy ScriptEngine实例,这样二次重建可以保证一定重新创建新的 Isolate。
客观说,这个问题不好重现,毕竟没有方法主动去触发后台Act清理,所以建议引擎开发人员加上GLSurefaceView的销毁后续处理机制,总感觉怎么改都会内存泄漏
有人有相关方面的研究结论,欢迎一起讨论