JAVA垃圾回收机制

2018-03-13  本文已影响0人  Jocelyn_b0e1
  1. 为什么要了解垃圾回收?
    当需要排查各种内存溢出、内存泄漏问题,当垃圾收集成为系统达到更高并发量的瓶颈时,就需要进行必要的监控和调节。

  2. 什么时候回收?

2.1 引用计数法:每当一个地方引用它时,计数器值就加1;当引用失效时,计数器减1;但无法解决对象循环引用的问题
2.2 可达性分析算法:对任何“活”的对象,一定能最终追溯到其存活在堆栈或静态存储区之中的引用。即一定有一条引用链可以将一个对象连到GC Roots。
可以作为GC Roots的对象包括:虚拟机栈(本地变量表)中引用的对象;方法区中类静态属性引用的对象和常量引用的对象;本地方法栈中JNI(即Native方法)引用的对象。

  1. 怎么回收?
    3.1 JAVA堆:新生代(Young)、老年代(Old)
    新声代又被划分为三个区域:Eden、From Survivor、To Survivor。
    image.png

3.2 Minor GC 是发生在新生代中的垃圾收集动作,所采用的是复制算法。
Full GC 是发生在老年代的垃圾收集动作,所采用的是标记-清除算法

当对象在 Eden ( 包括一个 Survivor 区域,这里假设是 from 区域 ) 出生后,在经过一次 Minor GC 后,如果对象还存活,并且能够被另外一块 Survivor 区域所容纳( 上面已经假设为 from 区域,这里应为 to 区域,即 to 区域有足够的内存空间来存储 Eden 和 from 区域中存活的对象 ),则使用复制算法将这些仍然还存活的对象复制到另外一块 Survivor 区域 ( 即 to 区域 ) 中,然后清理所使用过的 Eden 以及 Survivor 区域 ( 即 from 区域 ),并且将这些对象的年龄设置为1,以后对象在 Survivor 区每熬过一次 Minor GC,就将对象的年龄 + 1,当对象的年龄达到某个值时 ( 默认是 15 岁,可以通过参数 -XX:MaxTenuringThreshold 来设定 ),这些对象就会成为老年代。
但这也不是一定的,对于一些较大的对象 ( 即需要分配一块较大的连续内存空间 ) 则是直接进入到老年代。

在辨别出需要回收的对象后,JAVA虚拟机在回收时有不同做法。
“停止-复制”。先暂停程序的运行,然后将所有存活的对象从当前堆一个挨着一个复制到另一个堆。
采用这种方式时,新堆将保持紧凑排列。但在效率上却存在问题,第一,需要多一倍的维护空间;第二,当程序进入稳定状态后,可能只会产生少量垃圾,甚至没有垃圾,此时,复制式回收器仍然会将所有内存自一处复制到另一处。
“标记-清扫”。在寻找存活对象的过程中,对每一个存活对象打标记。当标记工作完成后,没有被标记的对象将被清理。
采用这种方式,在效率上有了很大的提升,但清理后剩下的堆空间是不连续的。
实际上,JAVA虚拟机在清理垃圾时采用一种“自适应”技术。
JAVA虚拟机会对回收操作进行监控,当对象很稳定,垃圾很少,回收效率降低时,切换到“标记-清扫”方式。当堆空间出现很多碎片时,就会切换回“停止-复制”方式。

上一篇 下一篇

猜你喜欢

热点阅读