简体   繁体   English

Android NDK:重启活动后如何清理本机代码?

[英]Android NDK: How to clean up native code after restarting activity?

All, 所有,

I'm aware that by default an activity will be killed and restarted when the screen orientation changes, or a keyboard is slid in or out. 我知道默认情况下,当屏幕方向改变或键盘滑入或滑出时,活动将被终止并重新启动。 (See Activity restart on rotation Android ). (请参阅Android上的活动重启 )。 My question is, what is the correct way to handle this from a Native code perspective? 我的问题是,从Native代码的角度处理这个问题的正确方法是什么? eg if I have a static block loading a native library and my app is restarted, how do I ensure that any memory in the native land is dealt with appropriately? 例如,如果我有一个静态块加载本机库并且我的应用程序重新启动,我如何确保本地的任何内存都得到适当处理? The problem is 问题是

When we rotate the device, it looks like a separate Thread pool is created and the old ones are never removed. 当我们旋转设备时,它看起来像是创建了一个单独的线程池,并且永远不会删除旧的线程池。 This means that every time someone turns the device, we have a ton more threads sitting idle and taking up memory 这意味着每当有人转动设备时,我们就会有更多线程闲置并占用内存

How do I ensure that this doesn't happen? 我如何确保不会发生这种情况? I see from the JNIExample page some notes at the bottom: 我从JNIExample页面看到底部的一些注释:

[*]Unresolved issues and bugs Even though the example is fully functional, there are a couple unresolved issues remaining, which I was not able to figure out so far. [*]未解决的问题和错误尽管该示例功能齐全,但仍有一些未解决的问题,到目前为止我无法弄清楚。 Problems appear when you start the activity, then press the Back button to hide it, and then start it again. 启动活动时出现问题,然后按“返回”按钮将其隐藏,然后再次启动。 In my experience, calls to native functions in such restarted activity will fail spectacularly. 根据我的经验,在这种重新启动的活动中调用本机函数将会失败。 callVoid() simply crashes with a segmentation fault, while calls to getNewData() and getDataString() cause JVM to abort with an error, because it is no longer happy with the globally cached object reference. callVoid()只是因为分段错误而崩溃,而对getNewData()和getDataString()的调用会导致JVM因错误而中止,因为它对全局缓存的对象引用不再满意。 It appears that activity restart somehow invalidates our cached object references, even though they are protected with NewGlobalRef(), and the activity is running within the original JVM (activity restart does not mean that JVM itself is restarted). 看起来活动重启会以某种方式使我们的缓存对象引用无效,即使它们受到NewGlobalRef()的保护,并且活动在原始JVM中运行(活动重启并不意味着JVM本身已重新启动)。 I don't have a good explanation on why that happens, so if you have any ideas, please let me know. 我没有很好的解释为什么会发生这种情况,所以如果您有任何想法,请告诉我。

Has this been solved? 这已经解决了吗?

Restarting in Android NDK is annoying. 重新启动Android NDK很烦人。 Any static data you have sticks around, because it reuses the process, so you need to manually reset anything that will be invalid on a new run (like any OpenGL texture or vertex buffer objects). 您有任何静态数据,因为它重用了该过程,因此您需要手动重置在新运行中无效的任何内容(如任何OpenGL纹理或顶点缓冲区对象)。 It gives you a new Java thread and new Java Application and other objects as well, so any cached global references to objects that would be new in a new instance of your app need to be cleared as well. 它还为您提供了一个新的Java线程和新的Java应用程序以及其他对象,因此任何对应用程序的新实例中都是新的对象的缓存全局引用也需要清除。

So the strategy I use is twofold: Minimize restarts, and nuke everything on restart. 所以我使用的策略是双重的:最小化重启,并在重启时核对一切。

You minimize restarts by handling the configChanges in-app, as it says in the answer to the question you linked. 您可以通过处理appChanges in-app来最小化重启,正如您在链接问题的答案中所说的那样。 Then opening a keyboard or rotating don't cause an app restart, which is as it should be for any app with non-trivial start up times. 然后打开键盘或旋转不会导致应用程序重新启动,这应该是任何具有非平凡启动时间的应用程序。

And when I detect that a new instance of my app has started, I release everything critical from the old instance at that point, including releasing any Java objects I held onto via NewGlobalRef. 当我检测到我的应用程序的新实例已经启动时,我会在那时从旧实例中释放所有关键内容,包括通过NewGlobalRef释放我保留的任何Java对象。 I tried to minimize static data, but the few unavoidable places where I do keep around static objects I clear them when I detect the new instance starting up. 我试图最小化静态数据,但是在我检测到新实例启动的时候,我在静态对象周围保留了几个不可避免的地方。

The old threads should go away once there are no more outstanding references to them (ie, once you've released all of your NewGlobalRef objects). 一旦没有更多未完成的引用(即,一旦释放了所有NewGlobalRef对象),旧线程就会消失。

If the VM is restarted, you start from scratch. 如果重新启动VM,则从头开始。 If not, the state is right where you left it. 如果没有,状态就在你离开的地方。 There is no invalidation of cached object references that yanks things out from under NewGlobalRef. 在NewGlobalRef下,没有任何缓存对象引用失效的东西。 I wrote a few other notes about the wooyd article on the NDK mailing list . 在NDK邮件列表上写了一些关于wooyd文章的其他说明。

If you have data that needs to be initialized when your activity is restarted, you should add an explicit initialization call to your activity (in onCreate, I think). 如果在重新启动活动时需要初始化数据,则应该为活动添加显式初始化调用(我认为在onCreate中)。 Make sure you properly discard any stuff you retained from the previous round -- DeleteLocalRef then store NULL, don't just memset() to zero. 确保你正确地丢弃你在上一轮中保留的任何东西 - DeleteLocalRef然后存储NULL,不要只将memset()归零。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM