先明确内存模型的基本结构,方便后面参数理解
JVM基本结构
image每一个Java虚拟机线程都有一个私有的Java栈。一个线程的Java栈在线程创建的时候 被创建。Java栈中保存着帧信息(参阅本章2.4节),Java栈中保存着局部变量、方法参 数,同时和Java方法的调用、返回密切相关。
本地方法栈和Java栈非常类似,最大的不同在于Java栈用于Java方法的调用,而本地 方法栈则用于本地方法调用。作为对Java虚拟机的重要扩展,Java虚拟机允许Java直接调 用本地方法(通常使用C编写)。
PC(Program Counter)寄存器也是每个线程私有的空间,Java虚拟机会为每一个Jav a线程创建PC寄存器。在任意时刻,一个Java线程总是在执行一个方法,这个正在被执行 的方法称为当前方法。如果当前方法不是本地方法,PC寄存器就会指向当前正在被执行的 指令。如果当前方法是本地方法,那么PC寄存器的值就是undefined。
执行引擎是Java虚拟机的最核心组件之一,它负责执行虚拟机的字节码。现代虚拟机 为了提高执行效率,会使用即时编译技术将方法编译成机器码后再执行。
堆空间一般结构
image堆、方法区、栈的关系
image堆内存 = 新生代 + 老年代
新生代 = 伊甸区 + from + to
一、最大堆与初始堆的设置 -Xms -Xmx
- -Xms
为JVM启动时申请的****初始****Heap值,默认为操作系统物理内存的1/64但小于1G。默认当空余堆内存大于70%时,JVM会减小heap的大小到-Xms指定的大小,可通过-XX:MaxHeapFreeRation来指定这个比列。
- -Xmx
-Xmx 为JVM运行时可申请的****最大****Heap值,默认值为物理内存的1/4但小于1G,默认当空余堆内存小于40%时,JVM会增大Heap到-Xmx指定的大小,可通过-XX:MinHeapFreeRation来指定这个比列。
- XX:MaxHeapFreeRation 、XX:MinHeapFreeRation
- xmx 不超过总内存的 70%(一般60% 足以) ,4G(物理内存)
2.8G 8G(物理内存)6G - 实际工作中,将-Xmx与-Xms设置成相等,可以有效的减少程序运行时的GC次数,从而提高性能
二、新生代的配置 -Xmn
- 堆中新生代的大小
设置较大的新生代会减小老年代的大小,对性能影响很大。
- 新生代一般设置为整个堆内存的1/3到1/4左右
- 参数-XX:SurvivorRatio用来设置新生代中eden空间和from/to空间的比例关系
-XX:SurvivorRatio=eden/from=eden/to
设置例子:
-Xmx20m -Xms20m -Xmn5m -XX:SurvivorRatio=2 -XX:+PrintGCDetails
- -XX:NewRatio
除了使用-Xmn指定新生代的绝对大小,还可以使用-XX:NewRatio来设置新生代与老年代的比例
-XX:NewRatio=老年代/新生代
设置例子:
-Xmx20M -Xms20M -XX:NewRatio=2 -XX:+PrintGCDetails
小结:
在实际工作中,应该根据系统的特点做合理的设置,基本策略是:尽可能将对象预留在新生代,减少老年代GC的次数
堆的分配参数示意图
image三、OOM错误信息输出
- 发生oom时输出到指定文件
发生OOM后,将站信息输出a.dump中
-Xmx20m -Xms5m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/a.dump
- 发生oom时执行指定脚本文件
-Xmx20m -Xms5m "-XX:OnOutOfMemoryError=D:/tools/jdk1.7_40/bin/
printstack.bat %p"
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/a.dump
四、堆外内存设置
方法区配置
- 方法区只要是存放类的元信息
- JDK1.6 与 JDK1.7 等版本中,-XX:PermSize和-XX:MaxPermSize配置永久区大小
-XX:PermSize : 初始永久区大小
-XX:MaxPermSize:最大永久区大小
- JDK1.8 永久区名称被废弃,使用元数据区存放元数据。
默认情况 下,元数据区只受系统可用内存的限制,但依然可以使用参数-XX:MaxMetaspaceSize指定 永久区的最大可用值。
栈配置 Stack Space
- 栈是每个线程私有的内存空间
- -Xss指定线程栈大小,此参数直接决定了函数的调用的最大深度。
- 线程栈的大小是个双刃剑,如果设置过小,可能会出现栈溢出,特别是在该线程内有递归、大的循环时出现溢出的可能性更大,如果该值设置过大,就有影响到创建栈的数量,如果是多线程的应用,就会出现内存溢出的错误.
- DK5.0以后每个线程堆 栈大小为1M,以前每个线程堆栈大小为256K。根据应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一 个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。
- JVM可创建的最大线程数限制因素:线程栈大小 》 进程的最大内存 》 操作系统位数
直接内存配置
在NIO中被广泛使用到,直接内存跳过了java堆,使java程序可以直接访问原生堆空间
最大可用直接内存可以使用参数-XX:MaxDirectMemorySize设置,如不设置,默认值 为最大堆空间,即-Xmx。当直接内存使用量达到-XX:MaxDirectMemorySize时,就会触发 垃圾回收,如果垃圾回收不能有效释放足够空间,直接内存溢出依然会引起系统的OOM。
网友评论