原生 C++库 - 谁必须释放内存以及如何释放?
这是关于安卓的。情况:
C++ 库和 java 包装类以及用于处理库中的 C++ 类的本机函数 (JNI)。当普通的java代码需要C++对象时,它会创建相应的java包装对象,该对象通过本机函数创建C++对象,并在“long”变量中记住指向本机对象的指针。在接下来的所有操作中,包装器都会将此指针提供给本机函数等。
问题:
如何在最后释放所有分配的 C++ 对象?目前每个包装类都有“finalize”方法,它调用本机函数来释放C++对象,但Android不保证“finalize”的调用!另一方面,通常 C++ 库不知道 Java 代码分配了多少个 C++ 对象以及什么类型。
当我们的java应用程序终止时,剩余分配的内存会发生什么?当操作系统卸载库时,Android会自动释放从本机库使用的整个堆吗?
This is about Android. The situation:
C++ library and java wrapper classes plus native functions (JNI) for working with C++ classes from the library. When common java code needs C++ object, it creates corresponding java wrapper object which creates C++ object through native function and remembers the pointer to the native object in 'long' variable. In all next actions the wrapper gives this pointer to the native functions etc.
The problem:
How to release all allocated C++ objects at the end? Currently every wrapper class has 'finalize' method where it calls native function for releasing of the C++ object, but Android doesn't guarantee the calling of 'finalize'! At the other side, normally the C++ library has no idea how many and what types of C++ objects are allocated by java code.
What will happens with the remaining allocated memory when our java application terminates, will Android release automatically the whole heap, used from the native library, when the OS unloads the library?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
在进程生命周期结束时,所有进程内存(Java 和 C++ 堆)将被系统释放和回收。但有一件事是,Android 活动关闭并不一定会结束该进程。我不确定那里的进程关闭政策是什么。
另一方面,依靠垃圾收集和 Finalize() 对我来说听起来像是可靠的设计。您声称 - “Android 不保证
finalize()
”。你有引用吗?因为如果它带有“当对象作为进程关闭的一部分被释放时......”的免责声明,那么我们仍然很好。如果您非常偏执,您可以编写自己的 malloc()/free()/realloc() 包装器,存储所有已分配对象的列表,并引入一个清理函数来遍历列表并释放所有对象。然而,包含的 Java 对象可能会以一种奇怪的僵尸状态结束,其中它们下面的内存已被释放。这是一个很棘手的命题,很容易出错。所以我仍然会说 - 对垃圾收集器有信心。缺乏它会......令人不安。
At the end of the process lifetime, all process memory (both Java and C++ heap) will be freed and reclaimed by the system. One thing is though, Android activity closing does not necessarily end the process. I'm not sure what's the process shutdown policy there.
On the other hand, relying on the garbage collection and finalize() sounds like solid design to me. You claim - "Android does not guarantee
finalize()
". Do you have a cite for that? 'Cause if it comes with a disclaimer of "when the object is freed as a part of process shutdown...", then we're still good.And if you're super-paranoid, you can write your own malloc()/free()/realloc() wrapper, store a list of all allocated objects, and introduce a cleanup function that walks the list and frees them all. The containing Java objects, however, might end in a weird zombie state where the memory has been freed from under them. This is a tricky proposition that is very easy to get wrong. So I'd still say - have faith in the garbage collector. Lack thereof would be... disturbing.
由于范式的差异,您必须将显式销毁合并到使用 C++ 资源在底层实现的 Java 对象中。所以一个
close()
或其他类似的方法。 JNI 也会出现同样的问题,因此这些问题的答案将适用于您:强制 Java 调用我的 C++ 析构函数 (JNI)
至于关闭时的内存问题,我认为通常最好不要依赖于此。如果你达到干净的状态,valgrind 等可以确保你没有泄漏。
但从技术角度来看,由于 Android 基于 Linux,我想它会做通常的事情,并在进程关闭时释放所有内存。利用这一点可以使程序退出比显式释放内存更快(仅适用于使用其他方法来确保保持程序正确性并且在运行时不会泄漏的专家)。
Due to the difference in paradigms, you have to incorporate explicit destruction into your Java objects that are implemented under the hood using C++ resources. So a
close()
or other such method. The same issue comes up with the JNI, so answers to those questions will apply to you:Force Java to call my C++ destructor (JNI)
As for the memory issue on closing, it's generally best in my opinion to not rely on this. If you get to a clean state, valgrind and such can make sure you weren't leaking.
But from a technical standpoint--since Android is based on Linux, I'd imagine it does the usual thing and will free all the memory when the process closes. Taking advantage of that can make your program exit faster than explicitly freeing memory (for experts only who use other methods to ensure this maintains program correctness and they aren't leaking at runtime).
我们正在使用 JNI,并且遇到了这样的问题。
实际上,问题在于我们重载了 Finalize() 来进行清理。我们通过删除 Finalize() 并创建一个 clean() 来解决问题。这个 clean() 调用执行适当删除的 JNI 函数(并将 C++ 指针设置为 null,以防万一)。我们调用 clean() 就像在 C++ 中使用 delete 一样(例如,当变量超出范围时)。
这对我们有用。我希望它对你有用。祝你好运!
We are using JNIs and we had a problem like that
Actually, the problem resided in the fact that we were overloading finalize() to do the clean up. We solved our problems by removing our finalize() and creating a clean() instead. This clean() calls the JNI function that does the appropriate deletes (and set the C++ pointers to null, just in case). We call clean() just as you would in C++ with delete (e.g. when the variable goes out of scope).
That worked for us. I hope it works for you. Good luck!