首页

关于JVM内存参数在不同场景需求优化设置,并对相关参数进行详细分析及实例说明

标签:java,jvm优化,tomcat,性能优化,内存调优,内存溢出,内存泄漏,OutOfMemoryOutOfMemoryError,StackOverflowError     发布时间:2015-05-24   

一、前言

对于32位为操作系统,每个进程最大内存使用空间为232 =4096MB,也就是理论上每个进程可使用的最大内存为4G,但是操作系统本身内核需要占用一半左右空间,所以jvm最大支持2G内存(实际达不到,根据具体系统实际占用使用情况而定,如我自己系统现在最大只能1.4G,如下图1-1所示),对于64位系统最大内存使用空间可到达16384PB,所以JVM可使用内存大小无上限

2015-05-25_144847.gif

(图1-1)

二、案例配置

1.对于高性能数据处理参数配置方案

服务器配置:4G MEM ,2CPU, JDK 1.6.X

参数配置:  -server  -XX:PermSize=196m  -XX:MaxPermSize=196m  -Xmn320m  -Xms768m  -Xmx1024m

解释说明:

[-XX:PermSize=196m -XX:MaxPermSize=196m]配置方法区大小(默认最小值为16MB,最大值为64MB),对于数据处理需要静态化大量数据及变量到这个区域,这个区域又称持久代,主要存放了要加载的信息(名称、修饰符等)、类中的静态变量、类中定义的final类型的常量、类中的Field信息、类中的方法信息,当方法区域超过允许大小是会抛出OutOfMemory的错误信息

[-Xmn320m] 或者设置-XX:NewSize=320m,设置年轻代威整个堆3/8原则,整个堆大小=年轻代大小+年老代大小+持久代大小;增加年轻代大小就等于减少年老代大小

[-Xms768m -Xmx1024m]根据系统情况设置堆内存大小;-Xms为jvm启动最小的内存,默认是物理内存的1/64小于1G,-Xmx为最大内存设置,默认是物理内存的1/4小于1G

2.高并发请求Web应用参数配置方案

服务器配置:8G MEM,8 CPU, JDK 1.6.X

参数配置:-server -Xmx3550m -Xms3550m -Xmn1256m -Xss128k -XX:SurvivorRatio=6 

-XX:MaxPermSize=256m   -XX:ParallelGCThreads=8 -XX:MaxTenuringThreshold=0 -XX:+UseConcMarkSweepGC

解释说明:

[-Xmx3550m -Xms3550m] Xmx 与 -Xms 相同以避免JVM反复重新申请内存。-Xmx 的大小约等于系统内存大小的一半,即充分利用系统资源,又给予系统安全运行的空间。

[-Xmn1256m] 设置年轻代大小m为1256MB。在整个堆内存大小确定的情况下,增大年轻代将会减小年老代,反之亦然。此值关系到JVM垃圾回收,对系统性能影响较大

[-Xss128k]设置较小的线程栈以支持创建更多的线程,支持海量访问,并提升系统性能,设置每个线程的栈大小。JDK5.0之前每个线程栈大小为256K,以后每个线程栈大小为1M。应当根据应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000左右。需要注意的是:当这个值被设置的较大(例如>4MB)时,将会在很大程度上降低系统的性能

[-XX:SurvivorRatio=6] 默认是8,设置年轻代中Eden区与Survivor区的比值设置为6,则2个Survivor区与1个Eden区的比值为2:6,一个Survivor区占整个年轻代的1/8。

[-XX:ParallelGCThreads=8]  配置并行收集器的线程数,此值配置为与CPU核数相等,为8个并行收集器一起工作

[-XX:MaxTenuringThreshold=0]  设置对象最大存活时间,对象不再年轻代幸存区直接进入老年代,增加对象缓存时间,减少数据库查询同时,减轻了I/O压力

[-XX:+UseConcMarkSweepGC]   设置年老代并发回收,降低Full GC出现概率

3.  对并发吞吐量的性能优

参数配置:-server   -Xmx3800m -Xms3800m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20

解释说明:   

[-Xmx3800m -Xms3800m] 配置了最大Java Heap来充分利用系统内存。

[-Xmn2g] 创建足够大的青年代(可以并行被回收)充分利用系统内存,防止将短期对象复制到老年代。

[-Xss128] 减少默认最大的线程栈大小,提供更多的处理虚拟内存地址空间被进程使用。

[-XX:+UseParallelGC] 采用并行垃圾收集器对年青代的内存进行收集,提高效率。

[-XX:ParallelGCThreads=20]减少垃圾收集线程,默认是和服务器可支持的线程最大并发数相同,往往不需要配置到最大值。

4.  对老年代优化配置

参数配置: -server -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20 -XX:+UseParallelOldGC

解释说明:

[-Xmx3550m -Xms3550m] 内存分配被减小,因为ParallelOldGC会增加对于Native Heap的需求,因此需要减小Java Heap来满足需求。 

[-XX:+UseParallelOldGC] 采用对于老年代并发收集的策略,可以提高收集效率。

5. 提高吞吐量,减少应用停顿时间

参数配置: -server   -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:ParallelGCThreads=20             -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:SurvivorRatio=8   -XX:TargetSurvivorRatio=90                                        -XX:MaxTenuringThreshold=31

解释说明:

[-XX:+UseConcMarkSweepGC -XX:+UseParNewGC] 选择了并发标记交换收集器,它可以并发执行收集操作,降低应用停止时间,同时它也是并行处理模式,可以有效地利用多处理器的系统的多进程处理

[-XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=31] 表示在青年代中Eden和Survivor比例,设置增加了Survivor的大小,越大的survivor空间可以允许短期对象尽量在年青代消亡。 

[-XX:TargetSurvivorRatio=90] 允许90%的空间被占用,超过默认的50%,提高对于survivor的使用率。

三、补充说明

JVM的内存结构组成:方法区、堆、本地方法栈、PC寄存器及方法栈(如图3-1)

1432567687078066686.jpg

(图3-1)

堆区:

    1. 存储对象实例及数组集合,所有通过new创建的对象内存都分配在Heap上,对象所占的内存有GC进行回收

    2. 堆区(heap)被线程所共享,不存放基本类型和对象引用,只存放实例数据

    3.如下图3-2,堆内存由年轻代(New Generation)、年老代(Old Generation)、持久代(Permanent Generation)

    年轻代:分3个区,1个Eden区,2个Survivor区(from 和 to)、垃圾回收即 Young GC,其中Eden大小通过-XX:NewSize和-XX:MaxNewSize参数来调整,Survivor是通过-XX:SurvivorRatio进行调整;-XX:NewRatio=4表示年轻代比年老代为1:4

    年老代:年轻代中经历了N次垃圾回收后仍然存活的对象,就会被复制到年老代,垃圾回收即 Full GC,年老代内存溢出:java.lang.OutOfMemoryError:Java heap space,通过-Xms和-Xmx来进行调整

持久代:存放静态类型数据,如 Java Class, Method 等,持久代内存溢出:java.lang.OutOfMemoryError:PermGen space,通过通过-XX:PermSize及-XX:MaxPermSize来进行调节

1432569137578025633.png

(图3-2)

PC寄存器及方法栈:

    1.每个线程均会创建PC寄存器和自己独立的栈区,PC寄存器占用的是CPU寄存器或系统内存,栈中只保存原始类型数据和对象引用(不是对象)

    2.每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问,当方法运行完毕时,其对应的栈帧所占用的内存会自动释放。

    3.栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)。

    4.当JVM方法栈空间不足时,会抛出StackOverflowError的错误,如下:

Exception in thread  "Thread-1"  java.lang.StackOverflowError

方法区:

    1.又叫静态区,也被线程共享。方法区存放了要加载类的信息(名称、修饰符等),具体包括定义的final类型的常量、类中的Field信息、类中的方法信息等

    2.见上文持久代部分

四、常见问题

1. 内存泄漏 - 是指分配内存垃圾回收器无法回收

2. 内存溢出 - 对象需申请的内存空间已超过系统配置范围

@b@