JVM内存分配与回收策略
java体系所长内存自动管理可归结为自动化的解决了两个问题:
1.给对象分配内存
2.回收分配给对象的内存
给对象分配内存 就是在堆上分配 但是也可能经过JIT编译后被拆散为标量类型间接的在栈上分配 对象主要分配在新生代的Eden区是哪个 如果启动了本地线程分配缓存 将按线程由现在TLAB上分配 少数情况下会分配在老年代中 分配规则并不是百分百固定的 器细节取决于当前虚拟机使用的是哪一种垃圾收集器组合
如果没有指定收集器组合的话默认使用 Serial/Serial Old 收集器 ParNew/Serial Old 收集器组合的规则也基本一致的内存分配和回收策略
对象优先在Eden区分配
大多数情况下 对象都会在Eden区 进行分配 当Eden区没有空间分配内存时虚拟机将发动一次Minor GC
虚拟机提供了-XX:+PrintGCDetails 参数 作为 收集器日志参数
如果申请大对象的话会直接进入老年代
所谓大对象就是指需要大量连续内存空间的java对象 大对象对于java虚拟机内存来说是一个坏消息 因为出现大对象容易导致内存还有不少空间就提前出发垃圾收集以获取足够的连续空间来 存放数据
虚拟机提供了一个 -XX:pretenureSizeThershold参数 这个参数可以使大于 该参数值的数据直接在老年代中分配 这样就可以避免在Eden 区和 两个Survivor 区之间大量内存拷贝(新生代复制收集算法)pretenureSizeThershold 只对Serial 和 ParNew两款收集器有效
长期存活的对象也会进入老年代
虚拟机既然通过分代收集思想来管理内存就必须识别哪些对象应该放在新生代利 虚拟机给每个对象了一个对象年龄计数器 在Eden出生并经过Minor GC后仍然存活 并且能被 Survivor 容纳的话将把对象存放在 Survivor 空间并将年龄+1对象在 Survivor 区经历过一次 Minor GC 年龄就增加一岁 当年龄达到一定程度(默认为15岁) 就会升级到老年代中 通过-XX:MaxTenuringThreshold 来设定
动态对象年龄判定
JVM一般都有动态对象年龄判定如果Survivor 空间中相同年龄大小的所有对象综合大于Survivor 空间的一般 年龄大于该年龄的对象 会直接进入老年代
空间分配担保
空间分配担保是什么每次发生Minor GC时 虚拟机会检测每次晋升到老年代的平均大小 是否大于老年代的剩余大小 如果大于则改为直接进行一次Full GC 小于则查看HandlePromotionFailure是否允许担保失败 如果允许就只会进行Minor GC 如果不允许则改为进行Full GC
新生代使用的是复制收集算法 为了内存的利用率 只使其中一个SurVivor 空间作为轮换备份 因此出现大量对象后在Minor GC后仍存在的情况就需要老年代进行分配担保 Survivor 存放不下的内存 直接进入年老代 前提是年老代有足够容纳对象的剩余空间