深入浅出JVM之GC算法与种类

1.GC的概念

Garbage Collection垃圾收集,在C或C++语言中,内存空间由程序员来释放,但是Java语言中程序员不会单独操作内存空间,所以内存释放需要由JVM来实现。在Java中,GC对象是堆空间和永久区。

2.引用计数法

老牌垃圾回收算法,通过计算对象的引用计数来标记对象是否是垃圾。该算法会为每个对象记录一下引用的次数,如果有一次引用就记录为1,如果有三次引用就标记为3,如果用完了释放对应的引用则将引用次数减1。当该对应的引用计数为0,那么就说明没有程序在使用该对象,那么该对象就可以被回收了。

引用计数法的问题:

引用和去引用都伴随加法和减法,影响性能

很难处理循环引用。对于循环引用的对象,每个对象的引用计数都为1,当跟对象不再对这个循环对象引用的时候,循环引用对象的计数无法都变为0,这就造成这些循环引用的对象无法被回收,内存也就无法正常释放了。

3.标记-清除:

标记清除算法是现代垃圾回收算法的思想基础,该算法将垃圾回收分为两个阶段,一个是标记阶段,一个是清除阶段。在标记阶段,标记所有从根节点开始的可达对象。未被标记的对象就是可以被回收的垃圾对象。在清除阶段,清除所有未被标记的对象。

4.标记-压缩:

标记压缩算法是对标记清除算法的一个改进,基本思路和标记清除算法一致,不一样的地方是标记压缩算法在清理阶段先将所有的存活对象压缩到内存的一端,然后清理边界外的所有空间。这样不会存在不连续的内存空间,有利于内存的有效利用。

5.复制算法:

复制算法是一种相对高效的回收方法,但是他不适合于存活对象较多的场合,比如老年代。该算法的基本思路是将原有的内存空间分为两块,每次只使用其中一块,在垃圾回收时,将正在使用的内存中的存活对象复制到未使用的内存块中,之后,清除正在使用的内存块中的所有对象,交换两个内存的角色,完成来及回收。

复制算法的问题是对空间的浪费。可以整合标记清理的思想来减少空间的浪费。

一种改进的算法是减少复制空间的大小,在发生GC的时候,大对象直接放到老年代里,因为复制空间可能很小,放不下大对象。在几次GC的时候都没有被回收的对象算是老年对象,老年对象也会放在老年代里。

由于复制算法的存在,在计算新生代的可用空间的时候就不能算上to space空间,所以根据内存分配的地址计算的空间大小=eden space+from space+to space,而实际可用空间是eden space+from space,通过PrintGCDetails命令看到的新生代的大小也是这个大小,to space的空间就被浪费了。

6.分代思想:

根据对象的存活周期(被引用的时间长短)进行分类,短命对象归为新生代,长命对象归为老年代。这两种对象的性质不一样,所以JVM在做垃圾回收的时候要区别对待,这样才能保证jvm的性能。对于少量的短命对象,也就是新生代,适合复制算法,对于大量长命对象,也就是老年代里的对象,适合标记清理或者标记压缩。

7.可触及性:

存在三种状态:

可触及的:

从根节点开始扫描,可以触及到这个对象。

可触及的:

指在当前状态下从根节点无法触及,但是在将来的某个时点可能再次被触及,就是可复活的对象,在这种状态下的对象也是不能被回收的。一个对象,一旦所有的引用被是否,那么就是可复活的状态,因为在finalize()方法中可能复活该对象。

不可触及的:

在调用在finalize()后,可能会进行不可触及状态,不可触及的对象不可能复活,是可以被回收的。

建议:避免使用finalize()方法,操作不慎可能导致错误。如果需要使用在方法的后面释放一些资源,可以使用try-catch-finally来替代它。finalize()方法的优先级比较低,何时被调用不确定,有时候是在GC的时候才会被调用,而何时方式GC是不确定的。

8.根:

栈中引用的对象。

方法区中的静态成员或者常量引用的对象(全局对象)

JNI方法栈中引用的对象

以上三种情况下的对象都可以视为根,都是可触及的,不会被GC回收。

9.Stop-The-World

Java中一种全局暂停的现象。全局停顿,所有的Java代码停止,只有native代码可以执行,但是不能和JVM交互。整个JVM都处于挂死的状态,不能执行应用程序。

一旦发生,多半由于GC引起:

Dump线程

Dump堆

死锁检查

JVM在做GC的时候需要对对象做标记,标记这些对象是否是垃圾对象,是否可以被回收,如果这是还不断有垃圾产生,则会陷入死循环,无法标记完所有的对象,所以当JVM在做GC的时候,JVM会停止其他的线程执行程序,等标记完对象后再重新执行程序。全局停顿的过程是无法避免的。一般新生代的GC时间比较短,老年代的GC时间可能比较长。有的老年代的GC时间可能长达几十分钟,在这段时间里系统将不可用,也无法访问。如果在生产环境上发生就可能造成生产环境的应用不可用,所以需要警惕和避免这种情况的发生。

发布了36 篇原创文章 · 获赞 2 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/xjjdlut/article/details/105241957