假如你现在还在为自己的技术担忧,假如你现在想提升自己的工资,假如你想在职场上获得更多的话语权,假如你想顺利的度过35岁这个魔咒,假如你想体验BAT的工作环境,那么现在请我们一起开启提升技术之旅吧,详情请点击
stop the world
在介绍垃圾回收算法之前,我们需要先了解一个词"stop the world",stop the world会在执行某一个垃圾回收算法的时候产生, JVM为了执行垃圾回收,会暂时java应用程序的执行,等垃圾回收完成后,再继续运行。如果你使用JMeter测试过java程序,你可能会发现在测试过程中,java程序有不规则的停顿现象,其实这就是"stop the world",停顿的时候JVM是在做垃圾回收。所以尽可能减少stop the world的时间,就是我们优化JVM的主要目标。接下来我们看一下目前有哪些常见垃圾回收的算法。
引用计数法
引用计数法顾名思义,就是对一个对象被引用的次数进行计数,当增加一个引用计数就加1,减少一个引用计数就减1。
image
上图表示3个Teacher的引用指向堆中的Teacher对象,那么Teacher对象的引用计数就是3,以此类推Student对象的引用计数就是2。
image
上图表示Teacher对象的引用减少为2,Student对象的引用减少为0(减少的原因是该引用指向了null,例如teacher3=null),按照引用计数算法,Student对象的内存空间将被回收掉。
引用计数算法原理非常简单,是最原始的回收算法,但是java中没有使用这种算法,原因有2。1是频繁的计数影响性能,2是它无法处理循环引用的问题。
例如Teacher对象中引用了Student对象,Student对象中又引用了
Teacher对象,这种情况下,对象将永远无法被回收。
其实最主要的原因是就是2的原因,我们来看一下2的具体案例
如上图所看到的的,大的区域是堆内存,小的空间是栈的局部变量表区域。
堆中两个对象相互引用,栈中的对象分别对应着,这个时候假如我们把引用断掉,这个时候垃圾回收机制是回收不了的,因为堆中的两块区域还相互引用着呢。
下面我们来看一下,java的spothot虚拟你采用的是不是这种机制。我们来看下面的代码
public class TestGC {
public Object instance;
private final static int _1M = 1024 * 1024; private byte[] bytesize = new byte[2*_1M]; public static void testGC() { TestGC A = new TestGC();
TestGC B = new TestGC();
A.instance = B;
B.instance = A;
- = null;
- = null;
System.gc();
} }
public class Test {
public static void main(String[] args) {
TestGC.testGC();
}
}
控制台打印:
[GC (System.gc()) [PSYoungGen: 5407K->552K(18944K)] 5407K->552K(62976K),
0.0434520 secs] [Times: user=0.00 sys=0.00, real=0.04 secs]
[Full GC (System.gc()) [PSYoungGen: 552K->0K(18944K)] [ParOldGen: 0K>517K(44032K)] 552K->517K(62976K), [Metaspace: 2661K->2661K(1056768K)],
0.0229769 secs] [Times: user=0.05 sys=0.00, real=0.02 secs] Heap
PSYoungGen total 18944K, used 164K [0x00000000eb300000,
0x00000000ec800000, 0x0000000100000000) eden space 16384K, 1% used
[0x00000000eb300000,0x00000000eb3290d0,0x00000000ec300000) from space 2560K, 0% used
[0x00000000ec300000,0x00000000ec300000,0x00000000ec580000) to space 2560K, 0% used
[0x00000000ec580000,0x00000000ec580000,0x00000000ec800000)
ParOldGen total 44032K, used 517K [0x00000000c1800000, 0x00000000c4300000,
0x00000000eb300000) object space 44032K, 1% used
[0x00000000c1800000,0x00000000c1881670,0x00000000c4300000)
Metaspace used 2668K, capacity 4486K, committed 4864K, reserved 1056768K class space used 282K, capacity 386K, committed 512K, reserved 1048576K 分析:
主要看:
[GC (System.gc()) [PSYoungGen: 5407K->552K(18944K)] 5407K->552K(62976K)
堆在gc回收前大小为5407k,gc后为552k;
说明两个对象并没有因为相互持有,造成循环引用,无法释放。间接证明JVM 并未采用 reference counting算法管理内存。延伸
控制台打印GC日志
1.右键项目或文件——Debug As——Debug Configurations
2.双击Java Application——VM arguments中填写-verbose:gc——Debug。
VM arguments参数配置:
-verbose:gc (开启打印垃圾回收日志)
-Xloggc:D:testgc.log (设置垃圾回收日志打印的文件,文件名称可以自定义)
-XX:+PrintGCTimeStamps (打印垃圾回收时间信息时的时间格式)
-XX:+PrintGCDetails (打印垃圾回收详情)
假如你现在还在为自己的技术担忧,假如你现在想提升自己的工资,假如你想在职场上获得更多的话语权,假如你想顺利的度过35岁这个魔咒,假如你想体验BAT的工作环境,那么现在请我们一起开启提升技术之旅吧,详情请点击