Fork me on GitHub

Java虚拟机---垃圾收集器和内存分配策略

Java对象内存分配策略和垃圾收集器

Java的内存管理主要是针对于对内存中的对象的分配和回收(堆和方法区)

垃圾收集算法

判断哪些对象需要回收

  1. 引用计数法:每个对象都有一个计数器,当这个对象被一个变量或者另一个对象引用的时候,计数器加一;若该引用失效便计数器减一。当计数器为0的时候,就认为该对象是无效对象
    • 缺点:很难解决对象之间互相循环引用的问题
  2. 可达性分析(主流):所有和GC Roots直接或间接相连的对象都是有效对象,和GC Roots没有引用链相连的对象就是无效对象

可作为GC Roots对象的类别

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

引用强弱

强引用>软引用>弱引用>虚引用

  1. 强引用:只要引用还在,那么垃圾收集器永远不会回收掉被引用的对象(Object object = new Object())
  2. 软引用:描述一些还有用但不是必需的对象。当第一次OOM之前,将会讲这些对象列进回收范围之中进行第二次回收。第二次内存还不足的话才会报OOM
  3. 弱引用:描述非必需对象。生存至下一次垃圾回收之前,也就是垃圾回收时,必回收弱引用关联的对象
  4. 虚引用:被回收时收到一个系统通知

回收无效对象的过程

  1. 判断对象是否覆盖了finalize()方法
    • 覆盖,且该方法的finalize()方法没有执行,就会将finalize()方法扔到F-Queue队列中
    • 没有覆盖,直接释放对象内存
  2. 执行F-Queue队列中的finalize()方法。如果出现耗时操作就会直接停止执行,将该对象清除
  3. 对象重生或者死亡,在执行finalize的过程中,若有引用则重生,没有则清除

垃圾收集算法

  1. 标记-清除算法
    • 标记需要被清除的对象
    • 标记完成后统一回收被标记的对象
    • 缺点:效率低、空间碎片多
  2. 复制算法(新生代)
    • 可用区域分为大小相等的两块
    • 一块用完,存活对象放置另一块,清理已使用的一块
    • 优点:简单、高效。缺点:代价过高(只能每次使用原来的一半)
  3. 标记-整理算法(老年代)
    • 先标记需要清理的对象
    • 所有存货对象向一端移动
    • 清理掉端边界以外的区域
  4. 分代收集算法(结合起来使用)

垃圾回收器

  1. 新生代
    • Serial、ParNew、Parallel Scavenge
  2. 老年代
    • CMS、Serial Old(MSC)、Parallel Old
  3. G1
  • Serial收集器
    1. 单线程收集器(只会使用一个CPU或者一条线程去完成垃圾收集器工作,更重要的是在进行垃圾收集工作的时候,必须暂停其他所有的工作线程,直至收集结束)
    2. 复制算法
  • ParNew收集器
    1. Serial收集器的多线程版本
    2. 复制算法
  • Parallel Scavenge收集器
    1. 并行多线程收集器
    2. 复制算法
    3. 可控制的吞吐量
    4. 适合后台计算不需要太多交互任务
  • Serial Old收集器
    1. 单线程收集器
    2. 标记-整理算法
  • Parallel Old收集器
    1. 多线程收集器
    2. 标记-整理算法
    3. 注重吞吐量和CPU资源敏感
  • CMS收集器
    1. 标记-清除算法
    2. 互联网或者B/S系统的服务端,重视响应速度
  • G1收集器
    1. 面向服务端
    2. 并发
    3. 分带手机算法
    4. 内存分配和回收策略

对象优先在Eden区中分配

  1. 堆中内存空间分为新生代和老年代
  2. 新生代(复制算法)进一步分为Eden区域 survior from区域 survior to区域
  3. 每次创建对象的时候,首先在Eden区进行分配。Eden区满则在 Survior from中分配,如果Survior from也满了,则启动分配担保,将这两区域的对象转移到老年代,重新再Eden区中分配新的对象

大对象直接进入老年代

大对象:占用大量连续存储空间的对象

生命周期较长的对象进入老年代

相同年龄的对象内存超过Survior内存一半的对象进入老年代

Minor GC

当Eden内存区域满了的时候,将Eden区域的内存碎片和Survior from区域的转移到Survior to 中

Full GC

老年代的内存区域满了之后,全部的内存区域都进行GC