JVM 内存分配和回收策略

  对象的内存分配,主要是在java堆上分配(有可能经过JIT编译后被拆为标量类型并间接地在栈上分配),如果启动了本地线程分配缓冲,将按线程优先在TLAB上分配。少数情况下也是直接分配到老年代,分配规则不是固定的,细节还是取决于垃圾收集器的组合,以及虚拟机和内存相关参数的配置。

   JVM 堆中分为 新生代 老年代 永久代,新生代分为 Eden区,SurvivorFrom区域和SurvivorTo区域  

         

关于这几个概念的说明,可以参考 :http://ju.outofmemory.cn/entry/346964

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

优先分配在Eden区

  大多数情况下,对象在新生代Eden区中分配。当Eden区中内存空间不足的时候,会进行一次Minor GC。

  Minor GC 与 Full GC (Major GC)
  Minor GC:指 发生在新生代的垃圾收集动作,因为新生代对象 "朝生夕死" 的特性,所以Minor GC非常频繁,一般回收的速度也快。
  Full GC:指发生在老年代的垃圾收集动作,Full GC的动作速度比较慢

大对象直接进入老年代

  大对象指的是,需要大量连续空间的java对象(例如数组和长字符串)。可以设置虚拟机参数:-XX:PretenureSizeThreshold  ,令大于这个参数的设置值的对象直接进入 老年代(-XX:PretenureSizeThreshold 参数只对 Serial 和 ParNew收集器有效,Parallel Scavenge收集器不识别这个参数)。

 
长期存活的对象进入老年代
  虚拟机给每个对象定义了一个年龄计数器(Age),如果对象在Eden分配了空间,当Minor GC发生后仍然存活,而且能够被Survivor容纳,则会移动到Survivor,并且Age +1,对象在Survivor区中每经历一次Minor GC,n年龄计数器则会+1,当达到一定程度(默认是15,这个阀值由参数 -XX:MaxTenuringThreshold 来设置),这个对象则会晋升到老年代中。
 
动态对象年龄判定
    为了适应各种应用程序的内存情况,虚拟机并不要求java对象的年龄达到MaxTenuringThreshold才会将其移入到老年代中。当在Survivor区内相同年龄的所有对象大小总和大于Survivor空间的一半时,这些对象将会移入到老年代中,而无需等待年龄达到 MaxTenuringThreshold 设置的值。
 
空间分配担保
    当发生Minor GC的时候,虚拟机将会检测之前每次晋升到老年代对象的平均大小是否大于老年代的剩余空间大小。(理解为根据之前晋升到老年代对象的平均大小的 "经验" 来判断老年代的的剩余空间是否足够存储那些即将晋升到老年代的对象)
  • 如果大于则进行一次Full GC
  • 如果小于则看 HandlePromotionFailure 设置是否允许担保失败,如果允许担保失败,则进行Minor GC,如果不允许,则再进行一次Full GC (大部分是打开允许的,为了避免频繁的 Full GC)。

猜你喜欢

转载自www.cnblogs.com/xiaojianfeng/p/9370052.html