sun.nio.ch.FileChannelImpl 中的 System.gc() 调用是坏情况吗?
Is the System.gc() call in sun.nio.ch.FileChannelImpl a bad case?
try {
// If no exception was thrown from map0, the address is valid
addr = map0(imode, mapPosition, mapSize);
} catch (OutOfMemoryError x) {
// An OutOfMemoryError may indicate that we've exhausted memory
// so force gc and re-attempt map
System.gc();
try {
Thread.sleep(100);
} catch (InterruptedException y) {
Thread.currentThread().interrupt();
}
try {
addr = map0(imode, mapPosition, mapSize);
} catch (OutOfMemoryError y) {
// After a second OOME, fail
throw new IOException("Map failed", y);
}
}
来自 jdk/FileChannelImpl.java at jdk8-b120.
这对异常恢复有帮助吗?
举个例子,问题是内存不足。因此,运行 垃圾收集器释放内存可能会解决这个问题。但是对 System.gc()
的调用只是对 JVM 的建议。不能保证垃圾收集器通过此调用释放任何内存。
所以这种方法有点启发式。
当对象分配失败并显示 OutOfMemoryError
时,垃圾收集器确实已经尽力回收未使用对象的内存或扩展堆。所以在捕获 OutOfMemoryError
之后调用 System.gc()
是没有意义的。
一种特殊情况是垃圾收集器反复回收少量内存,因此应用程序可以继续,但必须在下一次分配时执行另一次垃圾收集。当某些垃圾收集器检测到应用程序花费了超过 98% 的 CPU 时间用于垃圾收集时,它们会抛出 OutOfMemoryError
消息“超出 GC 开销限制”。在这种情况下,调用 System.gc()
会适得其反,因为那样的话,应用程序会花费更多的时间在垃圾收集以及创建和处理 OutOfMemoryError
上。
FileChannelImpl
的情况不同。 map0
可能由于本机内存不足而失败,或者在 32 位系统的情况下,当 运行 超出地址 space 时。在这些情况下,堆内存管理器没有产生 OutOfMemoryError
,垃圾收集器也可能没有产生 运行。但是要回收本机内存或地址 space,关联的 ByteBuffer
实例必须进行垃圾回收,因此它们的清理器可以 运行。这是一个罕见的角落案例,其中调用 System.gc();
是有意义的。
它仍然很脆弱,因为 System.gc();
不能保证收集所有对象或 运行 垃圾收集器。 JEP 383 应该通过更好地控制本机分配的生命周期来解决这个问题。
try {
// If no exception was thrown from map0, the address is valid
addr = map0(imode, mapPosition, mapSize);
} catch (OutOfMemoryError x) {
// An OutOfMemoryError may indicate that we've exhausted memory
// so force gc and re-attempt map
System.gc();
try {
Thread.sleep(100);
} catch (InterruptedException y) {
Thread.currentThread().interrupt();
}
try {
addr = map0(imode, mapPosition, mapSize);
} catch (OutOfMemoryError y) {
// After a second OOME, fail
throw new IOException("Map failed", y);
}
}
来自 jdk/FileChannelImpl.java at jdk8-b120.
这对异常恢复有帮助吗?
举个例子,问题是内存不足。因此,运行 垃圾收集器释放内存可能会解决这个问题。但是对 System.gc()
的调用只是对 JVM 的建议。不能保证垃圾收集器通过此调用释放任何内存。
所以这种方法有点启发式。
当对象分配失败并显示 OutOfMemoryError
时,垃圾收集器确实已经尽力回收未使用对象的内存或扩展堆。所以在捕获 OutOfMemoryError
之后调用 System.gc()
是没有意义的。
一种特殊情况是垃圾收集器反复回收少量内存,因此应用程序可以继续,但必须在下一次分配时执行另一次垃圾收集。当某些垃圾收集器检测到应用程序花费了超过 98% 的 CPU 时间用于垃圾收集时,它们会抛出 OutOfMemoryError
消息“超出 GC 开销限制”。在这种情况下,调用 System.gc()
会适得其反,因为那样的话,应用程序会花费更多的时间在垃圾收集以及创建和处理 OutOfMemoryError
上。
FileChannelImpl
的情况不同。 map0
可能由于本机内存不足而失败,或者在 32 位系统的情况下,当 运行 超出地址 space 时。在这些情况下,堆内存管理器没有产生 OutOfMemoryError
,垃圾收集器也可能没有产生 运行。但是要回收本机内存或地址 space,关联的 ByteBuffer
实例必须进行垃圾回收,因此它们的清理器可以 运行。这是一个罕见的角落案例,其中调用 System.gc();
是有意义的。
它仍然很脆弱,因为 System.gc();
不能保证收集所有对象或 运行 垃圾收集器。 JEP 383 应该通过更好地控制本机分配的生命周期来解决这个问题。