Java性能 -- JVM堆内存分配
JVM内存分配性能问题
- JVM内存分配不合理最直接的表现就是频繁的GC,这会导致上下文切换,从而降低系统的吞吐量,增加系统的响应时间
对象在堆中的生命周期
- 在JVM内存模型的堆中,堆被划分为新生代和老年代
- 新生代又被进一步划分为Eden区和Survivor区,Survivor区由From Survivor和To Survivor组成
- 当创建一个对象时,对象会被优先分配到新生代的Eden区
- 此时JVM会给对象定义一个对象年轻计数器(
-XX:MaxTenuringThreshold
)
- 此时JVM会给对象定义一个对象年轻计数器(
- 当Eden空间不足时,JVM将执行新生代的垃圾回收(Minor GC)
- JVM会把存活的对象转移到Survivor中,并且对象年龄+1
- 对象在Survivor中同样也会经历Minor GC,每经历一次Minor GC,对象年龄都会+1
- 如果分配的对象超过了
-XX:PetenureSizeThreshold
,对象会直接被分配到老年代
查看JVM堆内存分配
- 在默认不配置JVM堆内存大小的情况下,JVM根据默认值来配置当前内存大小
- 在JDK 1.7中,默认情况下新生代和老年代的比例是1:2,可以通过
–XX:NewRatio
来配置- 新生代中的Eden:From Survivor:To Survivor的比例是8:1:1,可以通过
-XX:SurvivorRatio
来配置
- 新生代中的Eden:From Survivor:To Survivor的比例是8:1:1,可以通过
- 若在JDK 1.7中开启了
-XX:+UseAdaptiveSizePolicy
,JVM会动态调整JVM堆中各个区域的大小以及进入老年代的年龄- 此时
–XX:NewRatio
和-XX:SurvivorRatio
将会失效,而JDK 1.8是默认开启-XX:+UseAdaptiveSizePolicy
- 在JDK 1.8中,不要随意关闭
-XX:+UseAdaptiveSizePolicy
,除非对堆内存的划分有明确的规划 - 每次GC后都会重新计算Eden、From Survivor、To Survivor的大小
- 计算依据是GC过程中统计的GC时间、吞吐量、内存占用量
- 此时
1 | $ java -XX:+PrintFlagsFinal -version | grep HeapSize |
1 | $ jmap -heap 10773 |
内存泄露 / 内存溢出
- 内存泄露:不再使用的对象无法得到及时的回收,持续占用内存空间,从而造成内存空间的浪费
- 内存溢出:如堆内存空间不足,栈空间不足,方法区空间不足等
- 关系:_内存泄露可能导致内存溢出,但内存溢出不一定是内存泄露导致的_
参考资料
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.