有哪些Java GC的相关问题

本文主要介绍“Java GC的相关问题有哪些”。在日常操作中,相信很多人对Java GC的相关问题有所怀疑。边肖查阅了各种资料,整理出简单易用的操作方法,希望能帮助大家解答“Java GC有哪些相关问题”的疑惑!接下来,请和边肖一起学习! Java GC 当遇到一个问题或者一个知识点的时候,我们要明白,明白要解决什么问题。说到Java GC,这个GC的目的是什么?显然是为了回收内存,因为内存是有限的。随着程序中创建的对象越来越多,如果回收,内存会越来越大,最后程序会出现异常。既然目的是回收内存,一个新的问题就出现了。哪些物品可以回收?什么时候回收?如何回收? 哪些对象可以被回收 简单来说,无用的物品是可以回收的。换句话说,如果定义一个对象是无用的呢?这里主要有两种方法,一种叫做引用计数法,另一种叫做可达性分析法。 引用计数意味着如果一个对象被另一个对象引用一次,该对象将有一个引用计数器,并且该计数器将增加一。如果释放,参考计数器将递减1。当引用计数器的计数为0时,表示该对象没有用,此时可以回收该对象。表面上看起来合情合理,容易实施,但仔细一想就会发现有问题。例如,如果对象A引用对象B,但对象B也引用对象A,那么此时对象A和对象B的引用计数器的计数不会为0,但这两个对象不会被其他对象引用。理论上,这两个物体是可以回收的。 从上面可以看出,这个方案是有问题的,会导致内存泄漏。然后又来了一个方案,就是可达性分析。 可达性分析 可达性分析是指从GCRoots的点往下搜索,当找不到引用链时,说明对象是垃圾。那么哪些对象可以被认为是根节点呢?Java栈中有对象,方法区有静态属性和常量,局部方法栈中有对象。依次从这些对象中向下搜索。如果未能到达根节点的对象是垃圾对象,则可以回收它们。 如下图所示,对象A、B、C可以找到与Roots节点的连接,但对象D、E、F找不到与Roots节点的连接,即无法到达,所以这三个对象是垃圾对象。 有哪些Java GC的相关问题 第1张 什么时候回收 以上两个方案解决了哪些物件可以回收,那么下一个问题就是什么时候回收?当排除人工调用时,垃圾收集总是在为新对象分配内存时发生。此时,如果内存空间不足,将触发垃圾收集。 我们知道哪些物品可以回收,什么时候应该回收,那么下一个问题就是如何回收。根据不同的实现方式,垃圾收集有许多不同的算法。例如,有标签移除算法、复制算法、标签排序算法和世代回收算法。以下是简要介绍。想了解更多的人可以自己研究。 标记清除算法 标记算法简单易懂,主要执行两个动作,一个是标记,另一个是清除和回收标记对象内存。这种算法的一个问题是会有严重的内存碎片。如下图所示: 有哪些Java GC的相关问题 第2张 从上图可以看出,内存回收后内存碎片严重,导致在分配一些大对象时内存不足,但整体内存确实足够。 复制算法的实现简单明了,就是把内存任意分成两部分,平时使用时只固定其中一部分。当需要GC时,幸存的对象被复制到另一部分,然后所有使用的内存被清理。下图: 有哪些Java GC的相关问题 第3张 从上图可以看出,清除标记的内存碎片问题已经解决,但很明显复制算法还有另一个问题,那就是内存利用率大幅下降,可用内存只有原来的一半。 标记整理算法 既然去除标记和复制算法各有优缺点,我们自然要思考这两种算法能否结合,于是出现了标记整理算法。标记阶段与标记算法相同,其中首先标记要回收的零件,

不过清除阶段不是直接清除,而是把存活的对象往内存的一端进行移动,然后清除剩下的部分。如下图:

有哪些Java GC的相关问题 第4张

标记整理的算法虽然可以解决上面两个算法的一些问题,但是还是需要先进行标记,然后进行移动,整个效率还是偏低的。

分代回收算法

分代回收算法是目前使用较多的一种算法,这个不是一个新的算法,只是将内存进行的划分,不同区域的内存使用不同的算法。根据对象的存活时间将内存的划分为新生代和老年代,其中新生代包含  Eden 区和 S0,S1。在新生代中使用是复制算法,在进行对象内存分配的时候只会使用 Eden 和 S0 区,当发生 GC 的时候,会将存活的对象复制到 S1  区,然后循环往复进行复制。当某个对象在进行了 15 次GC  后依旧存活,那这个对象就会进入老年代。老年代因为每次回收的对象都会比较少,因此使用的是标记整理算法。

垃圾回收器

讲完了垃圾回收算法,我们再看下垃圾回收器,每一种垃圾回收器都是不同时代的不同产物,都有其独特性。