JVM垃圾回收和内存分配策略

来源:互联网 发布:linux 3306监听命令 编辑:程序博客网 时间:2024/05/16 09:20

JVM的垃圾回收

JVM垃圾回收主要完成以下几个方面的工作:

  1. 哪些内存需要回收
  2. 什么时候回收
  3. 怎么回收

    问题一,有两个子问题需要回答

    • JVM内存布局中哪些部分进行垃圾回收?

      程序计数器、虚拟机栈、本地方法栈三个区域是与线程紧密相关的,每个栈帧分配的内存大小在编译期是可知的,并且会随着线程的结束而释放相应的内存。堆区和方法区所需的内存随着程序的运行而动态变化,是垃圾回收的主要区域。

    • 对象何时可以被回收?(对象存活判定算法
      即对象存活性判定问题。主要有两种策略来决定对象的“死与活”, 引用计数法和可达性分析法。
      引用计数法:为每个对象添加一个引用计数器,当引用计数器计数到0时,对象就不可能再被使用了。这种方法很直观,但是对对象间相互循环引用的情况不能进行垃圾回收。
      可达性分析法:从一系列的GCRootSet中的对象开始,根据引用关系构建引用关系链,在这些引用关系链中的对象是可达的,否则是不可达的。
      GCRootSet中的对象主要包括:方法栈帧中引用的对象、类的静态成员引用的对象,方法区中常量引用的对象,本地方法栈中引用的对象。

    问题二,垃圾回收的时间
    JVM中存在固定的垃圾回收线程,在某些时间执行垃圾回收算法。对不可达的对象,要经过两次标记过程:
    第一次,被标记并筛选,筛选准则是是否有必要执行finalize()方法。
    对于判定为有必要执行finalize()方法的对象,添加到F-Queue的队列中,并稍后由Finalizer线程去执行,(不承诺等它结束)。
    第二次,回收 “即将回收”集合中的对象。

    问题三,垃圾收集算法

    • 标记-清除算法
      标记过程就是判定对象是否可达的过程,清除即回收对应的区域。最基础的算法,缺点:效率问题,内存碎片。

    • 复制算法
      将可用内存空间分为大小相等的两块,每次只使用其中一块。当这一块内存即将用完时,将其中的存活对象复制到另外一块中去,并一次性清空本块内存。
      改进:根据%98对象都是朝生夕死,原理。新生代维持%10的空闲区(Eden + 2 Survivor),不够时由老年代分配担保。

    • 标记-整理算法
      适用于老年代中(多数对象都存活), 先标记,然后让所有对象向一端移动,清理掉端边界以外的对象。

    • 分代收集算法
      将堆分为新生代、老年代。老年代:标记整理算法,新生代:复制算法。

安全点(Safe Point): GC垃圾回收的暂停点。

垃圾收集器:实例

Serial收集器:单线程,Stop the World.
SerialOld:

ParNew收集器:Serial的多线程版本。

Parallel Scavenge 收集器:以吞吐量为控制目标。
停顿时间和吞吐量的矛盾:停顿时间关系到交互效果,吞吐量关系到CPU利用效率。减小新生代空间可以减小停顿时间,但是回收频率必须变高,因此吞吐量变小了。
ParallelOld: 用于老年代,控制吞吐量。

CMS:并发收集,低停顿。

G1收集器:

分配策略:对象优先在Eden区域,大对象直接进入老年代,长期存活的对象进入老年代(年龄阈值),动态年龄判定,空间分配担保。

0 0
原创粉丝点击