虽然我在使用结束时尽力清理JNI对象以释放本机内存,但仍有一些问题长期存在,浪费系统本机内存。
有没有办法强制GC优先收集这些JNI代理?
我的意思是有没有办法让GC专注于某种特定的对象,即JNI代理?
感谢。
答案 0 :(得分:2)
如果你在谈论在本机代码中分配的内存(以及扩展名,句柄),它不在JVM垃圾收集器的范围之内 - 它没有什么可以做的,所以你可以独立完成。如果你在完成后没有在本机代码中释放内存,它将会泄漏。
如果您指的是通过其访问本机代码的Java对象,则它们是完全正常的对象,当它们变得无法访问时将被收集。请注意,如果您使用本机代码固定Java对象(例如,使用GetByteArrayElements
,则必须释放它们(例如,使用ReleaseByteArrayElements
)。
如果您的本机代码必须在让Java对象运行之前释放资源,那么Java对象应该具有某种类型的dispose方法,该方法在调用时将释放本机资源并使Java对象无法进一步使用。只需调用dispose方法并让对象引用即可。
最后一件事,我知道一旦加载就无法卸载本机库。
答案 1 :(得分:1)
没有办法让GC“专注”某些类型的对象。我假设您在终结器中清理,并在以下时间运行终结器:
这意味着,为了尽可能快地清理资源,您需要:
示例:
class NativeResource {
private static native long allocate();
private static native void release(long handle);
private final long handle;
private boolean closed = false;
public NativeResource(){
handle = allocate();
}
/** Deallocates the native resources associated with this proxy. */
public void close() {
if (closed) throw new IllegalStateException("Already closed");
release(handle);
closed = true;
}
protected void finalize() throws Throwable {
try {
if (!closed) release(handle);
} finally {
super.finalize();
}
}
}
// Usage:
NativeResource nr = new NativeResource();
try {
// Use the resource for something
} finally {
nr.close(); // Make sure resource is closed even after exceptions
}
答案 2 :(得分:1)
你的GC心理模型是错误的。 GC不会收集对象然后释放它们。
GC收集实时对象。然后将所有其他内存定义为空闲。
对于具有终结器的对象,以及可能在堆栈上分配的对象的优化等,对此有皱纹,但这是正确的心理模型。
全局引用(通过JNI提供的持久引用形式)充当对象的根。 GC从根开始,并在查找活动对象时递归跟随所有链接。如果删除全局引用,则它将停止使引用的对象保持活动状态。然后,GC可以回收对象使用的内存,但仅在没有任何其他引用的情况下,并且仅在后续收集期间回收。没有通用的方法来回收任何特定对象子集的内存。