JVM参数调优
一.OS不同情况的设置
一般情况下,64位的OS性能比32位的好。但是根据Sun官方说明,32位的JVM反而比64位的JVM性能要好。这里并不是建议大家使用32位JVM,只是说可以在64位OS系统环境下,调优效果不大可以尝试换成32位的JVM。
具体启动命令加入-d32
,可以启用32位JVM(如果可用的话):
java -d32 -jar jarfile [args...]
二.JVM内存模型及参数调优
JVM内存并不是设置越大越好。太大会造成寻址计算和垃圾回收开销过大,太小资源又不够用。先讲一下JVM每个区的作用。
可以从上图看到,JVM内存结构大分类上可以分为Non-Heap和Heap。
1.Non-Heap
官方定义:
Non-heap memory includes a method area shared among all threads and memory required for the internal processing or optimization for the Java VM.
简单翻译:Non-heap(非堆区)主要是由被线程共享的方法区和Java虚拟机内部进程所需内存组成。
具体说明:
name | 说明 | 相关JVM参数 | 回收情况 |
---|---|---|---|
CodeCache | 代码缓冲区,用于JIT编译和保存本地代码(Native code)所需的内存。 | -XX:ReservedCodeCacheSize java7默认值48M,java8默认值250M。 默认值已经够用,一般不会去修改。出现下列情况,可以根据情况修改这个参数值: 1.出现Hotspot编译失败。(增加) 2.为了减少JVM内存。(减少) | 不回收 |
Permanent Generation space | 持久代。主要存放类加载信息、类结构信息、类常量、类方法等等。 | Java1.7: -XX:PermSize -XX:MaxPermSize 默认值64M 一般来说默认的PermSize已经够用,但是如果应用里用到了很多动态加载,那可能就需要根据需要调整一下MaxPermSize大小 Java1.8: -XX:MetaspaceSize 默认值:20m -XX:MaxMetaspaceSize 默认值:机器最大内存 | FullGC时回收 |
Direct Memory | 暂定为持久代一部分。使用java.nio.ByteBuffer类的allocateDirect方法分配的内存,NIO基本上都是采用这个区域来交互数据。 | -XX:MaxDirectMemorySize 默认值为最大可用堆空间。当调用allocateDirect方法时,都会先去判断是否达到最大堆内存,如果达到则先调用System.gc()清理内存。对于采取NIO的应用,建议手动设置-XX:MaxDirectMemorySize的大小,避免内存浪费。 | FullGC时回收 |
2.Heap
官方定义:
Heap memory is the runtime data area from which the Java VM allocates memory for all class instances and arrays.The heap may be of a fixed or variable size. The garbage collector is an automatic memory management system that reclaims heap memory for objects.
堆区的基本管理过程:
创建的新对象开始放在Eden区,在MInor GC后剩余对象放入Survivor区(To Survivor或者From Survivor区**<因为采用的复制算法>**,如果Survivor区容量不够,直接放入Tenured区),在经过多次Minor GC后依然存活的对象放入Tenured区。等Tenued区容量不够时,就会触发Full GC。
对于堆区的参数调优,主要是:合理调整新生代和老年代的大小,让对象尽量在新生代就被Minor GC回收掉,减少Full GC的次数,Full GC的时候会发生"stop the world”。
JVM调优参数:
参数 | 说明 | 调优建议 |
---|---|---|
-Xms | Heap Size最小值 | 1.最好设置为应用正常时消耗的内存大小。 2.Java Performance推荐大小: Xmx 和 Xms设置为老年代存活对象的3-4倍,即FullGC之后的老年代内存占用的3-4倍 3.原因: 过大:增加GC时间,浪费内存。 过小:JVM性能浪费在申请内存上。 |
-Xmx | Heap Size最大值 | 1.设置为应用最大峰值时所消耗的内存。 2.Java Performance推荐大小: Xmx 和 Xms设置为老年代存活对象的3-4倍,即FullGC之后的老年代内存占用的3-4倍 3.原因: 太大浪费内存,计算寻址过大降低性能。 |
-Xmn | YoungGen大小 | 1.Xmn=1/3Xmx 2.Java Performance推荐大小: Xmn设置为老年代存活对象的1-1.5倍。 3.原因: 过大:导致Minor GC时间过长。 过小:频繁导致拷贝到老年代,影响性能。 具体可以根据应用的特点来进行设置,如果缓存数据多,新建对象少的话可以稍微小一点。如果每次请求都会创建较多对象,就要稍微设置大一点。 |
-XX:NewSize | 新生代初始值 | |
-XX:MaxNewSize | 新生代最大值 | -XX:NewSize和-XX:MaxNewSize这两个设置相对于-Xmn来说要灵活一点,对于需要新生代时大时小的情况,这种配置一个范围由于-Xmn。 |
-XX:SurvivorRatio | 新生代中Eden区和两个Survivor区的比值 | 注意Survivor区是两个,也就是说SurvivorRatio=3的话,实际上是Eden:to Survivor:from Survivor=3:1:1。默认为8。 tips:ParallelScavenge系的GC最初设计默认打开AdaptiveSizePolicy的,它会自动、自适应的调整各种参数。JVM参数中不显式设置而采用默认值并且UseAdaptiveSizePolicy不关掉的话,可能造成比例不为默认值。 |
三.垃圾收集器选择
JVM提供了三种垃圾收集器:
垃圾收集器 | 说明 |
---|---|
串行收集器 | -XX:+UseSerialGC 串行收集使用单线程处理所有垃圾回收工作,实现容易,效率比较高。但是无法使用多处理器的优势,所以此收集适合单处理器机器。当然,此收集器也可以用在小数据量(100M 左右)情况下的多处理器机器上。 |
并行收集器 | 新生代:-XX:+UseParallelGC 老年代:-XX:+UseParallelOldGC 线程数:-XX:ParallelGCThreads 最大垃圾回收暂停时间:-XX:MaxGCPauseMillis,如果设置了这个参数,堆大小和垃圾回收相关参数会进行调整以达到指定值。可能会减少应用的吞吐量。 吞吐量:-XX:GCTimeRatio,公式为 1/(1+N)。例如,-XX:GCTimeRatio=19 时,表示 5%的时间用于垃圾回收。默认情况为 99,即 1%的时间用于垃圾回收。 |
并发收集器 | -XX:+UseConcMarkSweepGC 可能出现的问题: 由于在垃圾回收过程中,不中止,这也意味着边回收,程序会生产新垃圾。这可能出现一个问题,垃圾还没有回收完,堆就消耗满,结果出现“Concurrent Mode Failure”错误。解决这个问题,通过“-XX:CMSInitiatingOccupancyFraction”参数来设置还有多少剩余堆空间时开始执行并发收集。 |
参考资料:
《深入理解Java虚拟机:JVM高级特性与最佳实践》
《Java进程JVM参数调优指导》