文章目录
1. System.gc() 的作用
System.gc()
的作用是建议虚拟机进行一次 Full GC,但是虚拟机可以拒绝这个 GC 请求。
GC 线程是一种守护线程
2. System.gc() 源码
/**
* Indicates to the VM that it would be a good time to run the
* garbage collector. Note that this is a hint only. There is no guarantee
* that the garbage collector will actually be run.
*/
public static void gc() {
boolean shouldRunGC;
synchronized(lock) {
shouldRunGC = justRanFinalization;
if (shouldRunGC) {
justRanFinalization = false;
} else {
runGC = true;
}
}
if (shouldRunGC) { //justRanFinalization=true
Runtime.getRuntime().gc();
}
}
从源码可以看出,只有当justRanFinalization=true
的时候才会执行垃圾收集。
而当调用runFinalization()
的时候,justRanFinalization 会变为 true
/**
* Provides a hint to the VM that it would be useful to attempt
* to perform any outstanding object finalization.
*/
public static void runFinalization() {
boolean shouldRunGC;
synchronized(lock) {
shouldRunGC = runGC;
runGC = false;
}
if (shouldRunGC) {
Runtime.getRuntime().gc();
}
Runtime.getRuntime().runFinalization();
synchronized(lock) {
justRanFinalization = true;
}
}
其实当我们直接调用System.gc()
只会把这次 GC 请求记录下来,等到justRanFinalization=true
的时候才会去执行 GC,justRanFinalization=true
之后会允许一次system.gc()
。之后再 call System.gc()
时还会重复上面的行为。
所以System.gc()
要跟System.runFinalization()
要一起搭配使用才能确保虚拟机执行垃圾收集。
查看ZygoteInit.java
,发现gc()
和runFinalizationSync()
是配合使用的,这样才有效果
ZygoteInit 是 c 到 java 的入口,也是 java 的第一个进程
它的 main 方法主要做了三件事:
- 建立 socket 服务端
- 启动各种系统服务如 ams,wms,pms…
- 进入死循环,等待和处理 ams 通过 socket 传递的请求
static void gcAndFinalize() {
final VMRuntime runtime = VMRuntime.getRuntime();
/* runFinalizationSync() lets finalizers be called in Zygote,
* which doesn't have a HeapWorker thread.
*/
System.gc();
runtime.runFinalizationSync();
System.gc();
}
3. 如何保证 System.gc() 有效
执行以下代码即可
System.gc();
System.runFinalization();
System.gc();
不过不建议这么做,因为 JVM 有自己的 GC 策略,根本不需要我们手动申请 GC
4. System.gc() 与 Runtime.getRuntime().gc() 的区别
- 垃圾回收是一种动态存储管理技术,它自动地释放不再被程序引用的对象,当一个对象不再被引用的时候,按照特定的垃圾收集算法来实现资源自动回收的功能。
- 每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接。可以通过
getRuntime()
方法获取当前运行时。 java.lang.System.gc()
实际上也是调用了java.lang.Runtime.getRuntime().gc()
,两者的行为没有任何不同。public static void gc() { Runtime.getRuntime().gc(); }
- 唯一的区别就是
System.gc()
写起来比Runtime.getRuntime().gc()
简单点。其实基本没什么机会用到这个命令,因为这个命令只是建议 JVM 安排 GC 运行,还有可能完全被拒绝。 GC 本身会周期性的自动运行,由 JVM 决定运行的时机,而且现在的 JVM 版本有多种更智能的模式可以选择,还会根据运行的机器自动去做选择,就算真的有性能上的需求,也应该去对 GC 的运行机制进行微调,而不是通过使用这个命令来实现性能的优化。