文章目录
三、堆内存详解和参数总结
主要总结HotSpot JVM 1.8 版本。
3.1 jvm内存概述
Java 堆是Java 虚拟机所管理的内存中最大的一块,是所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例以及数组都在这里分配内存。
堆内存分为年轻代和老年代,HotSpot JVM把年轻代分为了三部分:1个Eden区和2个Survivor区(分别叫from和to),默认比例为8:1。
栈内存归属于单个线程,也就是每创建一个线程都会分配一块栈内存,而栈中存储的东西只有本线程可见,属于线程私有。
3.2 内存相关参数
3.2.1 堆内存参数
堆内存大小
JVM有动态调整内存策略,通过-Xms,-Xmx 指定堆内内存动态调整的上下限。 在JVM初始化时实际只分配部分内存,可通过-XX:InitialHeapSize指定初始堆内存大小,未被分配的空间为图中virtual部分。年轻代和老年代在每次GC的时候都有可能调整大小,以保证存活对象占用百分比在特定阈值范围内,直到达到Xms指定的下限或Xms指定的上限。(阈值范围通过-XX:MinHeapFreeRatio, XX:MaxHeapFreeRatio指定,默认值分别为40, 70)。
年轻代内存大小
GC调优中还有个的重要参数是老年代和年轻代的比例,通过-XX:NewRatio设定,与此相关的还有-XX:MaxNewSize和-XX:NewSize,分别设定年轻代大小的上下限,-Xmn则直接指定年轻代的大小。
通过将-XX:MaxNewSize和-XX:NewSize设置成相同的值,可以固定年轻代的大小(同理:将-Xms和-Xmx设置成相同的值,能固定堆内存的大小),这与设置-XX:NewRatio 相比,能更精细的控制年轻代的内存大小。
Survivor区和Eden区内存大小
通过-XX:SurvivorRatio设置年轻代中Eden区和Survivor区的比值。例如设置年轻代中Eden区和Survivor区的比值设置为4,则Eden去和两个Survivor区的比值为4:2,一个Survivor去占整个年轻代的1/6。
3.2.2 栈内存参数
通过-Xss设置每个线程的堆栈大小。JDK5.0以后每个线程默认大小为1M,以前每个线程大小为256K。根据应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。
3.2.3 方法区内存参数
JDK1.8之前,永久代还没有彻底移除之前,通过-XX:PermSize设置方法区的初始值,通过-XX:MaxPermSize设置方法区的最大值。
JDK1.8之后,方法区被彻底移除了,取而代之的是元空间,而元空间使用的是本地内存。通过-XX:MetaspaceSize和-XX:MaxMetaspaceSize设置元空间的最小内存和最大内存。(Metaspace 的初始容量并不是 -XX:MetaspaceSize 设置,具体参考:JVM参数MetaspaceSize的误解)
3.3 垃圾收集相关参数
3.3.1 垃圾回收器
为了提高应用程序的稳定性,选择正确的垃圾收集算法至关重要。JVM 具有四种类型的 GC 实现:
- 串行垃圾收集器
- 并行垃圾收集器
- CMS 垃圾收集器
- G1 垃圾收集器
可以使用以下参数声明这些实现:
-XX:+UseSerialGC
-XX:+UseParallelGC
-XX:+UseParNewGC
-XX:+UseG1GC
3.3.2 垃圾收集参数
GC并发线程数可以通过JVM启动参数: -XX:ParallelGCThreads=N 来指定。在未明确指定的情况下,JVM会根据逻辑核数ncpus,采用以下公式来计算默认值 :
当ncpus小于8时,ParallelGCThreads = ncpus
否则 ParallelGCThreads = 8 + (ncpus - 8 ) ( 5/8 )
注意:在JRE版本1.8.0_131之前,JVM无法感知Docker的CPU限制,会使用宿主机的逻辑核数计算默认值。
3.4 配置项总结
分类 | 配置项 | 描述 | 配置解释 | 举例 | 默认值 |
---|---|---|---|---|---|
堆内存 | -Xms [heap size] [unit] | 最小堆大小 | heap size 表示要初始化内存的具体大小。unit 表示要初始化内存的单位。单位为 “ g” (GB)、“ m”(MB)、“ k”(KB) | -Xms2G | |
堆内存 | -Xmx [heap size] [unit] | 最大堆大小 | 同上 | -Xmx5G | |
栈内存 | -Xss [stack size] [unit] | 每个线程的堆栈大小 | stack size 表示栈内存大小,unit 表示要初始化内存的单位。单位为 “ g” (GB)、“ m”(MB)、“ k”(KB) | -Xss255K | JDK5.0以后每个线程默认大小为1M,以前每个线程大小为256K |
堆内存 | -XX:MinHeapFreeRatio=[minimum] | 可改变JVM最小剩余堆内存大小比例,增大到指定最大内存 | -XX:MinHeapFreeRatio=50 | 40 一般不用配置 | |
堆内存 | -XX:MaxHeapFreeRatio=[maximum] | 可改变JVM最大剩余堆内存大小比例,减小到指定最小内存 | -XX:MaxHeapFreeRatio=60 | 70 一般不用配置 | |
年轻代 | -Xmn [young size] [unit] | 设置年轻代大小 | 同Xms | -Xmn256m | |
年轻代 | -XX:NewSize=[young size] [unit] | 新生代最小值 | |||
年轻代 | -XX:MaxNewSize=[young size] [unit] | 新生代最大值 | |||
年轻代 | -XX:NewRatio=[num] | 设置年轻代(包括Eden和两个Survivor区)与老年代的比值 | 设置年轻代(包括Eden和两个Survivor区)与老年代的比值设置为4,则年轻代与老年代所占比值为1:4,年轻代占整个堆栈的1/5。 | -XX:NewRatio=4 | 2 |
年轻代 | -XX:SurvivorRatio=[num] | 设置年轻代中Eden区和Survivor区的比值 | 设置年轻代中Eden区和Survivor区的比值设置为4,则Eden去和两个Survivor区的比值为4:2,一个Survivor去占整个年轻代的1/6。 | -XX:SurvivorRatio=6 | 8 |
永久代 | -XX:MetaspaceSize=N | 指定元空间首次扩充的大小 | Metaspace 的初始容量并不是 -XX:MetaspaceSize 设置,无论 -XX:MetaspaceSize 配置什么值,对于 64 位 JVM 来说,Metaspace 的初始容量都是 21807104(约 20.8m) | 默认为20.8M | |
永久代 | -XX:MaxMetaspaceSize=N | 指定元空间的最大空间 | 默认为容器剩余的所有空间 | ||
直接内存 | -XX:MaxDirectMemorySize | 设置堆外内存最大值 |