JVM 如何 GC

JVM 如何 GC

管理对象

  • 引用技术算法
  • 给对象中添加一个引用计数器,每当有一个地方引用它时,计数器的值就加1
  • 当引用失效时,计数器的值就减1,任何时刻计数器为0的对象就是不可能在被使用了
  • 这种算法是很简单的,而且早期很多面向对象语言中都采用这种方式,但是现在主流的Java虚拟机中并没有采用这种方式来管理对象,其原因最主要的原因是它很难解决对象之间的相互循环引用。
  • 可达性分析算法
  • 通过一系列的称谓“GC Roots"的对象作为起始点
  • 从这些节点开始向下搜索,搜索所有走过的路径为引用链,当一个对象到GC Roots没有任何引用链项链时,则证明此对象时不可用的!
JVM 如何 GC

  • 上面的这张图,对象object5、object6、object7虽然互相没有关联,但是它们到GC Roots是不可达的,所以它们将会被判定为是可回收的对象
  • 注意:Java语言中,可作为GC Roots的对象包括下面几种:
  1. 虚拟机栈(栈帧中的本地变量表)中引用的对象
  2. 方法区中类静态属性引用的对象
  3. 方法区中常量引用的对象
  4. 本地方法栈中JNI(即一般说的Native方法)引用的对象

内存管理

  • 在程序运行过程当中,会创建大量的对象,这些对象,大部分是短周期的对象,小部分是长周期的对象
  • 对于短周期的对象,需要频繁地进行垃圾回收以保证无用对象尽早被释放掉
  • 对于长周期对象,则不需要频繁垃圾回收以确保不进行无谓地垃圾扫描检测。为解决这种矛盾,JVM的内存管理采用分代的策略:
  • 年轻代(Young Gen):
  • 存放新创建的对象
  • 内存大小相对会比较小,垃圾回收会比较频繁
  • 年轻代分成1个Eden Space和2个Suvivor Space(命名为A和B)
  • 当对象在堆创建时,将进入年轻代的Eden Space。垃圾回收器进行垃圾回收时,扫描Eden Space和A Suvivor Space,如果对象仍然存活,则复制到B Suvivor Space,如果B Suvivor Space已经满,则复制 Old Gen。扫描A Suvivor Space时,如果对象已经经过了几次的扫描仍然存活,JVM认为其为一个Old对象,则将其移到Old Gen。扫描完毕后,JVM将Eden Space和A Suvivor Space清空,然后交换A和B的角色(即下次垃圾回收时会扫描Eden Space和BSuvivor Space。
  • Young Gen垃圾回收时,采用将存活对象复制到到空的Suvivor Space的方式来确保不存在内存碎片,采用空间换时间的方式来加速内存垃圾回收。
  • 年老代(Tenured Gen):
  • JVM认为比较old的对象(经过几次的Young Gen的垃圾回收后仍然存在)
  • 内存大小相对会比较大,垃圾回收也相对没有那么频繁(比如可能几个小时一次)
  • 年老代主要采用压缩的方式来避免内存碎片(将存活对象移动到内存片的一边),当然,有些垃圾回收器(比如CMS垃圾回收器)出于效率的原因,可能会不进行压缩。
  • 持久代(Perm Gen):
  • 存放类定义、字节码和常量等很少会变更的信息

造成 full gc 的原因

  • new 了很多对象,没有即时在主动释放掉->Eden 内存不够用->不断把对象往 old 迁移->old 满了->full gc​
JVM 如何 GC


分享到:


相關文章: