这篇文章主要介绍“有哪些Java GC的相关问题”,在日常操作中,相信很多人在有哪些Java GC的相关问题问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”有哪些Java GC的相关问题”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
Java GC
目标
遇到一个问题或者一个知识点,我们要理解和明白是要解决什么问题的。说到 Java GC 那这个 GC 的目的是什么呢?很显然是回收内存,因为内存是有限的,随着程序中创建的对象越来越多,如果进行回收就会导致内存越来越大,最后程序就会出现异常。既然目的是为了回收内存,那么新的问题来了,哪些对象可以被回收呢?什么时候进行回收呢?怎么回收呢?
哪些对象可以被回收
简单来说就是无用的对象可以被回收,那么换句话说,如果定义一个对象是无用的呢?这里主要有两种方法,一个叫引用计数法,一个叫可达性分析法。
引用计数
引用计数说的是如果一个对象被别的对象进行了一次引用,那么该对象会有一个引用计数器,这个计数器就会加一;如果被释放一下,引用计数器就会减一。当引用计数器的计数为 0 的时候就表示这个对象是无用的,此时就可以对这样对象进行回收了。表面上看好像挺合理的,实现起来也很方便,但是仔细一想就会发现有问题。既循环引用的问题,比如对象 A 引用了对象 B,但是对象 B 当中也引用了对象 A,那么这个时候对象 A 和对象 B 的引用计数器的计数都不会是 0,但是这两个对象都没有被其他对象引用,理论上来说这两个对象都是可以被回收的。
从上面看到,这种方案是有问题的会导致内存泄露。随之而来的就出现了另一种方案,可就是可达性分析。
可达性分析
可达性分析说的是从 GCRoots 的点作为起点,向下搜索,当找不到任何引用链的时候表示该对象为垃圾对象。那么哪些对象可以被认为是 Roots 节点呢?有 Java 栈中的对象,方法区的静态属性和常量以及本地方法栈中的对象。从这几种对象依次向下搜索,如果没有能达到 Roots 节点的对象就是垃圾对象,就说明可以被回收。
如下图所有,对象 A,B,C都能找到与 Roots 节点的联系,但是对象 D,E,F 三个并不能找到与 Roots 节点的联系,也就是不可达,所以 DEF 这三个对象就是垃圾对象。
什么时候回收
上面的两种方案解决了哪些对象能被回收,那么下个问题,就是什么时候进行垃圾回收呢?在排除人为调用的时候,垃圾回收都是发生在为新生对象进行内存分配的时候,这个时候如果内存空间不足就会触发 GC 进行垃圾回收。
怎么回收
上面我们知道了哪些对象可以被回收,也知道我们应该什么时候进行回收,那下面要解决的就是如何进行垃圾回收了。垃圾回收根据实现的方式不同有多种不同的算法实现。比如有标记清除算法,复制算法,标记整理算法,分代回收算法,下面简单介绍一下,想深入了解的可以自行去研究一下。
标记清除算法
标记清除算法很好理解,主要就是执行两个动作,一个是标记,另一个是对进行标记的对象内存进行清除回收。这个算法有个问题就是会出现内存碎片化严重。如下图所示:
从上图中可以看到,在进行内存回收后出现了严重的内存碎片化,这就导致在分配某些大对象的时候仍然会出现内存不够的情况,但是总体内存确是够的。
复制算法
复制算法的实现方式比较简洁明了,就是霸道的把内存分成两部分,在平时使用的时候只用其中的固定一份,在当需要进行 GC 的时候,把存活的对象复制到另一部分中,然后将已经使用的内存全部清理掉。如下图:
从上图可以看到解决了标记清除的内存碎片化问题,但是很明显复制算法有另一个问题,那就是内存的使用率大大下降,能使用的内存只有原来的一半了。
标记整理算法
既然标记清除和复制算法各有优缺点,那自然的我们就想到是否可以把这两种算法结合起来,于是就出现了标记整理算法。标记阶段是标记清除算法一样,先标记出需要回收的部分,不过清除阶段不是直接清除,而是把存活的对象往内存的一端进行移动,然后清除剩下的部分。如下图:
标记整理的算法虽然可以解决上面两个算法的一些问题,但是还是需要先进行标记,然后进行移动,整个效率还是偏低的。
分代回收算法
分代回收算法是目前使用较多的一种算法,这个不是一个新的算法,只是将内存进行的划分,不同区域的内存使用不同的算法。根据对象的存活时间将内存的划分为新生代和老年代,其中新生代包含 Eden 区和 S0,S1。在新生代中使用是复制算法,在进行对象内存分配的时候只会使用 Eden 和 S0 区,当发生 GC 的时候,会将存活的对象复制到 S1 区,然后循环往复进行复制。当某个对象在进行了 15 次GC 后依旧存活,那这个对象就会进入老年代。老年代因为每次回收的对象都会比较少,因此使用的是标记整理算法。
垃圾回收器
讲完了垃圾回收算法,我们再看下垃圾回收器,每一种垃圾回收器都是不同时代的不同产物,都有其独特性。
Serial 垃圾收集器(单线程、复制算法)
ParNew垃圾收集器(Serial+多线程)
Parallel Scavenge 收集器(多线程复制算法、高效)
SerialOld收集器(单线程标记整理算法)
ParallelOld收集器(多线程标记整理算法)
CMS收集器(多线程标记清除算法)
G1收集器
各个垃圾收集器的配合使用情况可以参考下图,个人觉得对这么多的收集器没有必要全部精通,可以注重关注一下 CMS 和 G1 就可以了。感兴趣的小伙伴可以自己的研究一下。
到此,关于“有哪些Java GC的相关问题”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。