JVM(3)-垃圾收集器与内存分配策略

169 阅读2分钟

如何判断对象为垃圾对象

引用计数法

给对象添加一个引用计数器,每当有个对象引用它时,计数器加1;引用失效时计数器减1;为0时对象不可能被再引用。

没有使用的原因:很难解决对象之间相互循环引用的问题

可达性分析算法

看作为GC Roots的对象作为起始点,和它连通的是可用的,反之不可用

如下情况的对象可以作为GC Roots:

  • 虚拟机栈(栈桢中的本地变量表)、本地方法栈中JNI(Native方法)中的引用的对象
  • 方法区中的类静态属性引用的对象
  • 方法区中的常量引用的对象

当对象不可达时,会执行fianlize(),但该方法自会被自动调用一次,有点像c++的析构函数,书上说最好别用。

引用的分类

  • 强引用:Objece obj = new Object(),永远不会被垃圾搜集回收
  • 软引用:SoftReference类实现,可以存活第一次回收,但第二次就GG
  • 弱引用:WeakReference类实现,第一次就GG
  • 虚引用:PhantomReference类实现,不能通过它取得实例,唯一作用就是当该对象被回收时会收到一个系统通知。

如何回收

垃圾收集算法

  • 标记-清除算法:(老年代)先标记,再清除。缺点:效率低,内存碎片化
  • 复制算法:(新生代)HotSpot虚拟机把内存分为Eden和2块Survivor区,把在Eden和Survivor中 存活的对象 复制到空闲的一块Survivor中。不够时可以向老年代担保。
  • 标记-整理算法:(老年代)标记 -> 移动到一起 -> 清理
  • 分代收集算法:把内存分为新生代和老年代。根据年代选则合适的算法。

垃圾收集器

新生代 老年代 特殊
Serial(单线程) Serial Old(单线程,CMS备胎) G1(Region优先级回收)
ParNew(多线程) CMS(并发)
Parallel Scavenge(关注吞吐量)
  • 并行(Parallel):多条垃圾收集线程并行工作,但此时用户线程仍处于等待状态。
  • 并发(Concurrent):用户线程与垃圾收集线程同时执行。

如何分配

以HosSpot收集器的分配和回收策略为例

  • 优先分配在Eden
  • 大对象直接进入老年代
  • 长期存活的对象进入老年代
  • 动态对象年龄判定
  • 空间分配担保