Java.lang.System.gc() 是 Java.lang.Runtime.getRuntime.gc() 缩写。


Java System.gc()工作原理 与 JVM何时真真正正进行垃圾回收?

Java System.gc()工作原理?

JVM虚拟机何时真真正正的进行垃圾回收工作?

首先JDK5的API:

ba604ef33689c7caa50f5203.jpg
当调用System.gc()方法后系统运行垃圾回收器,调用gc()方法来建议JVM努力回收没有使用的对象内存,为了使它们占用的内存腾出来让别的对象快速使用。当调用完该方法后,JVM会尽它最大努力从所有不再使用(销毁)的对象中回收内存空间。

System.gc() 与 Runtime.getRuntime().gc()功能相同。

其实我们调用垃圾回收器进行回收的时候,JVM并不一定去真的回收,因为该方法只是建议与提醒JVM该回收了,JVM到底做与不做由它自身说了算。

最典型的例证是你将AWT或者Swing窗口dispose()掉,然后调用System.gc()回收,而后再调用show()仍能恢复到dispose前的窗口状态,也就是System.gc()根本就没有回收资源。

那么JVM到底什么时候真真正正的去回收垃圾呢?我做如下例子:

public static void main(String[] args) {
boolean flag = true;
int i = 0;
while(flag){
Window1 window = new Window1();
window.setVisible(true);
if(i == 999){
flag = false;
}
i++;
window.dispose();
double total = Runtime.getRuntime().totalMemory();
double free = Runtime.getRuntime().freeMemory();
System.out.println("No." + i +
" 可用内存: " + total +
" 剩余内存 : " + + free +
" 使用内存所占百分比: " + getP(total, free));
}
}

public static String getP(double a, double b){
double p3 = (a - b)/a;
NumberFormat nf = NumberFormat.getPercentInstance();
nf.setMinimumFractionDigits( 1 );
return nf.format(p3);
}

我这里进行1000次循环生成新的窗口和dispose()掉,观察内存占用情况,由于结果数据量较大,我就取其中比较典型的几个节点:

No.1 可用内存: 2031616.0 剩余内存 : 1591960.0 使用内存所占百分比: 21.6%

No.49 可用内存: 2031616.0 剩余内存 : 1091360.0 使用内存所占百分比: 46.3%
No.50 可用内存: 2031616.0 剩余内存 : 1077392.0 使用内存所占百分比: 47.0%
No.51 可用内存: 2031616.0 剩余内存 : 1062864.0 使用内存所占百分比: 47.7%
No.52 可用内存: 2031616.0 剩余内存 : 1410248.0 使用内存所占百分比: 30.6%
No.53 可用内存: 2031616.0 剩余内存 : 1397608.0 使用内存所占百分比: 31.2%

No.136 可用内存: 2031616.0 剩余内存 : 781512.0 使用内存所占百分比: 61.5%
No.137 可用内存: 2031616.0 剩余内存 : 769336.0 使用内存所占百分比: 62.1%
No.138 可用内存: 2031616.0 剩余内存 : 1136664.0 使用内存所占百分比: 44.1%
No.139 可用内存: 2031616.0 剩余内存 : 1130232.0 使用内存所占百分比: 44.4%

No.222 可用内存: 2031616.0 剩余内存 : 515064.0 使用内存所占百分比: 74.6%
No.223 可用内存: 2031616.0 剩余内存 : 500168.0 使用内存所占百分比: 75.4%
No.224 可用内存: 2031616.0 剩余内存 : 880504.0 使用内存所占百分比: 56.7%
No.225 可用内存: 2031616.0 剩余内存 : 864384.0 使用内存所占百分比: 57.5%

No.265 可用内存: 2031616.0 剩余内存 : 380600.0 使用内存所占百分比: 81.3%
No.266 可用内存: 2031616.0 剩余内存 : 368312.0 使用内存所占百分比: 81.9%
No.267 可用内存: 2031616.0 剩余内存 : 737640.0 使用内存所占百分比: 63.7%
No.268 可用内存: 2031616.0 剩余内存 : 721600.0 使用内存所占百分比: 64.5%

No.700 可用内存: 3051520.0 剩余内存 : 123256.0 使用内存所占百分比: 96.0%
No.701 可用内存: 3051520.0 剩余内存 : 111208.0 使用内存所占百分比: 96.4%
No.702 可用内存: 3776512.0 剩余内存 : 1843352.0 使用内存所占百分比: 51.2%
No.703 可用内存: 3776512.0 剩余内存 : 1831856.0 使用内存所占百分比: 51.5%

No.1000 可用内存: 3776512.0 剩余内存 : 610536.0 使用内存所占百分比: 83.8%

这里内存占用最高的是NO.701,达到96.4%,然后就急转直下到51.2%,其它典型节点的变化也是如此,从上面数据可以大致分析出JVM垃圾回收器的工作时间出发点应该是内存到达影响JVM后续工作的时候,它才会自动去执行垃圾回收操作。而根本就不需要我们去担心,我不知道JVM引擎是如何工作的,但是可以肯定的是JVM的智能程度要比C++强大的多,这也充分体现了Java的简单性。

本人: 1》 对于JVM的智能程度比C++强大的这个问题,我认为二者不能同位而语。前者只是一个在C/C++ Runtime中

运行Java程序而设计的虚拟机,而后者是一种语言。

2》程序部分,我个人没有进行测试。

3》System.gc()只是告知JVM要进行内存回收,至于什么时机回收则由JVM根据一定的算法和内存的使用情况决定。下面是收集的资料,可以借鉴下:

(1) GC是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的显示操作方法。
(2) 对于GC来说,当程序员创建对象时,GC就开始监控这个对象的地址、大小以及使用情况。通常,GC采用有向图的方式记录和管理堆(heap)中的所有对象。通过这种方式确定哪些对象是"可达的",哪些对象是"不可达的"。当GC确定一些对象为"不可达"时,GC就有责任回收这些内存空间。可以。程序员可以手动执行System.gc(),通知GC运行,但是Java语言规范并不保证GC一定会执行。
(3) 垃圾回收是一种动态存储管理技术,它自动地释放不再被程序引用的对象,当一个对象不再被引用的时候,按照特定的垃圾收集算法来实现资源自动回收的功能。
(4) System.gc();就是呼叫java虚拟机的垃圾回收器运行回收内存的垃圾。
(5) 当不存在对一个对象的引用时,我们就假定不再需要那个对象,那个对象所占有的存储单元可以被收回,可通过System.gc()方法回收,但一般要把不再引用的对象标志为null为佳。
(6) 每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接。可以通过 getRuntime 方法获取当前运行时。 Runtime.getRuntime().gc();
(7) java.lang.System.gc()只是java.lang.Runtime.getRuntime().gc()的简写,两者的行为没有任何不同。
(8) 唯一的区别就是System.gc()写起来比Runtime.getRuntime().gc()简单点. 其实基本没什么机会用得到这个命令, 因为这个命令只是建议JVM安排GC运行, 还有可能完全被拒绝。 GC本身是会周期性的自动运行的,由JVM决定运行的时机,而且现在的版本有多种更智能的模式可以选择,还会根据运行的机器自动去做选择,就算真的有性能上的需求,也应该去对GC的运行机制进行微调,而不是通过使用这个命令来实现性能的优化。