JVM参数配置及详解-Xms-Xmx-Xmn-Xss调优总结
堆⼤⼩设置
JVM 中最⼤堆⼤⼩有三⽅⾯限制:
①、相关操作系统的数据模型(32-bt还是64-bit)限制;
②、系统的可⽤虚拟内存限制;
③、系统的可⽤物理内存限制.
32位系统下,⼀般限制在1.5G~2G;64为操作系统对内存⽆限制.在Windows Server 2003 系统,3.5G物理内存,JDK5.0下测试,最⼤可设置为1478m.
堆内存逻辑上分为三部分:新⽣区+养⽼区+永久代
物理上分为两部分:新⽣+养⽼
Jdk1.7之前,有永久代,但已经逐步“去永久代”
Jdk1.8之后,⽆永久代,由元空间替代
典型设置:
java -Xmx3550m -Xms3550m -Xmn2g -Xss128k
①、-Xmx3550m:设置JVM最⼤可⽤内存为3550M.
②、-Xms3550m:设置JVM促使内存为3550m.此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存.
③、-Xmn2g:设置年轻代⼤⼩为2G.整个堆⼤⼩=年轻代⼤⼩ + 年⽼代⼤⼩ + 持久代⼤⼩.持久代⼀般固定⼤⼩为64m,所以增⼤年轻代后,将会减⼩年⽼代⼤⼩.此值对系统性能影响较⼤,Sun官⽅推荐配置为整个堆的3/8.
④、-Xss128k:设置每个线程的堆栈⼤⼩.JDK5.0以后每个线程堆栈⼤⼩为1M,以前每个线程堆栈⼤⼩为256K.更具应⽤的线程所需内存⼤⼩进⾏调整.在相同物理内存下,减⼩这个值能⽣成更多的线程.但是操作系统对⼀个进程内的线程数还是有限制的,不能⽆限⽣成,经验值在
3000~5000左右.
java -Xmx3550m -Xms3550m -Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:MaxPermSize=16
m -XX:MaxTenuringThreshold=0①、-XX:NewRatio=4:设置年轻代(包括Eden和两个Survivor区)与年⽼代的⽐值(除去持久代).设置为4,则年轻代与年⽼代所占⽐值为1:4,年轻代占整个堆栈的1/5
②、-XX:SurvivorRatio=4:设置年轻代中Eden区与Survivor区的⼤⼩⽐值.设置为4,则两个Survivor区与⼀个Eden区的⽐值为2:4,⼀个Survivor 区占整个年轻代的1/6
③、-XX:MaxPermSize=16m:设置持久代⼤⼩为16m.
④、-XX:MaxTenuringThreshold=0:设置垃圾最⼤年龄.如果设置为0的话,则年轻代对象不经过Survivor区,直接进⼊年⽼代. 对于年⽼代⽐较多的应⽤,可以提⾼效率.如果将此值设置为⼀个较⼤值,则年轻代对象会在Survivor区进⾏多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概论.
回收器选择
JVM给了三种选择:串⾏收集器,并⾏收集器,并发收集器,但是串⾏收集器只适⽤于⼩数据量的情况,所以这⾥的选择主要针对并⾏收集器和并发收集器.默认情况下,JDK5.0以前都是使⽤串⾏收集器,如果想使⽤其他收集器需要在启动时加⼊相应参数.JDK5.0以后,JVM会根据当前系统配置进⾏判断.
吞吐量优先的并⾏收集器
如上⽂所述,并⾏收集器主要以到达⼀定的吞吐量为⽬标,适⽤于科学技术和后台处理等.
典型配置:
java -Xmx3800m -Xms3800m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20
①、-XX:+UseParallelGC:选择垃圾收集器为并⾏收集器.此配置仅对年轻代有效.即上述配置下,年轻代使⽤并发收集,⽽年⽼代仍旧使⽤串⾏收集.
②、-XX:ParallelGCThreads=20:配置并⾏收集器的线程数,即:同时多少个线程⼀起进⾏垃圾回收.此值最好配置与处理器数⽬相等.
java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20 -XX:+UseParallelOldGC
①、-XX:+UseParallelOldGC:配置年⽼代垃圾收集⽅式为并⾏收集.JDK6.0⽀持对年⽼代并⾏收集.
java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:MaxGCPauseMillis=100
①、-XX:MaxGCPauseMillis=100:设置每次年轻代垃圾回收的最长时间,如果⽆法满⾜此时间,JVM会⾃动调整年轻代⼤⼩,以满⾜此值.
java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:MaxGCPauseMillis=100 -XX:+UseAdaptiveSizePolicy
①、-XX:+UseAdaptiveSizePolicy:设置此选项后,并⾏收集器会⾃动选择年轻代区⼤⼩和相应的Survivor区⽐例,以达到⽬标系统规定的最低相应时间或者收集频率等,此值建议使⽤并⾏收集器时,⼀直打开.
响应时间优先的并发收集器
如上⽂所述,并发收集器主要是保证系统的响应时间,减少垃圾收集时的停顿时间.适⽤于应⽤服务器,电信领域等.
典型配置:
java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:ParallelGCThreads=20 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC
①、-XX:+UseConcMarkSweepGC:设置年⽼代为并发收集.测试中配置这个以后,-XX:NewRatio=4的配置失效了,原因不明.所以,此时年轻代⼤⼩最好⽤-Xmn设置.
②、-XX:+UseParNewGC:设置年轻代为并⾏收集.可与CMS收集同时使⽤.JDK5.0以上,JVM会根据系统配置⾃⾏设置,所以⽆需再设置此值.
java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseConcMarkSweepGC -XX:CMSFullGCsBeforeCompaction=5 -XX:+UseCMSCompactAtFullCollection
①、-XX:CMSFullGCsBeforeCompaction=5:由于并发收集器不对内存空间进⾏压缩,整理,所以运⾏⼀段时间以后会产⽣"碎⽚",使得运⾏效率降低.此值设置运⾏多少次GC以后对内存空间进⾏压缩,整理.
②、-XX:+UseCMSCompactAtFullCollection:打开对年⽼代的压缩.可能会影响性能,但是可以消除碎⽚
辅助信息
JVM提供了⼤量命令⾏参数,打印信息,供调试使⽤.主要有以下⼀些:
-XX:+PrintGC
输出形式:[GC 118250K->113543K(130112K), 0.0094143 secs]
[Full GC 121376K->10414K(130112K), 0.0650971 secs]
-XX:+PrintGCDetails
输出形式:[GC [DefNew: 8614K->781K(9088K), 0.0123035 secs] 118250K->113543K(130112K), 0.0124633 secs]
[GC [DefNew: 8614K->8614K(9088K), 0.0000665 secs][Tenured: 112761K->10414K(121024K), 0.0433488 secs] 121376K-
>10414K(130112K), 0.0436268 secs]
-XX:+PrintGCTimeStamps -XX:+PrintGC:PrintGCTimeStamps可与上⾯两个混合使⽤
输出形式:11.851: [GC 98328K->93620K(130112K), 0.0082960 secs]
-XX:+PrintGCApplicationConcurrentTime:打印每次垃圾回收前,程序未中断的执⾏时间.可与上⾯混合使⽤
输出形式:Application time: 0.5291524 seconds
-
XX:+PrintGCApplicationStoppedTime:打印垃圾回收期间程序暂停的时间.可与上⾯混合使⽤
输出形式:Total time for which application threads were stopped: 0.0468229 seconds
-XX:PrintHeapAtGC:打印GC前后的详细堆栈信息
输出形式:
34.702: [GC {Heap before gc invocations=7:
def new generation total 55296K, used 52568K [0x1ebd0000, 0x227d0000, 0x227d0000)
eden space 49152K, 99% used [0x1ebd0000, 0x21bce430, 0x21bd0000)
from space 6144K, 55% used [0x221d0000, 0x22527e10, 0x227d0000)
to space 6144K, 0% used [0x21bd0000, 0x21bd0000, 0x221d0000)
tenured generation total 69632K, used 2696K [0x227d0000, 0x26bd0000, 0x26bd0000)
the space 69632K, 3% used [0x227d0000, 0x22a720f8, 0x22a72200, 0x26bd0000)
compacting perm gen total 8192K, used 2898K [0x26bd0000, 0x273d0000, 0x2abd0000)
the space 8192K, 35% used [0x26bd0000, 0x26ea4ba8, 0x26ea4c00, 0x273d0000)
ro space 8192K, 66% used [0x2abd0000, 0x2b12bcc0, 0x2b12be00, 0x2b3d0000)
rw space 12288K, 46% used [0x2b3d0000, 0x2b972060, 0x2b972200, 0x2bfd0000)
34.735: [DefNew: 52568K->3433K(55296K), 0.0072126 secs] 55264K->6615K(124928K)Heap after gc invocations=8:
def new generation total 55296K, used 3433K [0x1ebd0000, 0x227d0000, 0x227d0000)
eden space 49152K, 0% used [0x1ebd0000, 0x1ebd0000, 0x21bd0000)
from space 6144K, 55% used [0x21bd0000, 0x21f2a5e8, 0x221d0000)
to space 6144K, 0% used [0x221d0000, 0x221d0000, 0x227d0000)
tenured generation total 69632K, used 3182K [0x227d0000, 0x26bd0000, 0x26bd0000)
the space 69632K, 4% used [0x227d0000, 0x22aeb958, 0x22aeba00, 0x26bd0000)
compacting perm gen total 8192K, used 2898K [0x26bd0000, 0x273d0000, 0x2abd0000)
the space 8192K, 35% used [0x26bd0000, 0x26ea4ba8, 0x26ea4c00, 0x273d0000)
ro space 8192K, 66% used [0x2abd0000, 0x2b12bcc0, 0x2b12be00, 0x2b3d0000)
rw space 12288K, 46% used [0x2b3d0000, 0x2b972060, 0x2b972200, 0x2bfd0000)
}
, 0.0757599 secs]
-Xloggc:filename:与上⾯⼏个配合使⽤,把相关⽇志信息记录到⽂件以便分析.
常见配置汇总
堆设置
-Xms:初始堆⼤⼩
-Xmx:最⼤堆⼤⼩
-
XX:NewSize=n:设置年轻代⼤⼩
-XX:NewRatio=n:设置年轻代和年⽼代的⽐值.如:为3,表⽰年轻代与年⽼代⽐值为1:3,年轻代占整个年轻代年⽼代和的1/4
-XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的⽐值.注意Survivor区有两个.如:3,表⽰Eden:Survivor=3:2,⼀个Survivor区占整个年轻代的1/5
-XX:MaxPermSize=n:设置持久代⼤⼩
收集器设置
-XX:+UseSerialGC:设置串⾏收集器
-XX:+UseParallelGC:设置并⾏收集器
-XX:+UseParalledlOldGC:设置并⾏年⽼代收集器
-XX:+UseConcMarkSweepGC:设置并发收集器
垃圾回收统计信息
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:filename
并⾏收集器设置
-XX:ParallelGCThreads=n:设置并⾏收集器收集时使⽤的CPU数.并⾏收集线程数.
-XX:MaxGCPauseMillis=n:设置并⾏收集最⼤暂停时间
-XX:GCTimeRatio=n:设置垃圾回收时间占程序运⾏时间的百分⽐.公式为1/(1+n)
并发收集器设置
-XX:+CMSIncrementalMode:设置为增量模式.适⽤于单CPU情况.
-XX:ParallelGCThreads=n:设置并发收集器年轻代收集⽅式为并⾏收集时,使⽤的CPU数.并⾏收集线程数.
调优总结
年轻代⼤⼩选择
响应时间优先的应⽤:尽可能设⼤,直到接近系统的最低响应时间限制(根据实际情况选择).在此种情况下,年轻代收集发⽣的频率也是最⼩的.同时,减少到达年⽼代的对象.
吞吐量优先的应⽤:尽可能的设置⼤,可能到达Gbit的程度.因为对响应时间没有要求,垃圾收集可以并⾏进⾏,⼀般适合8CPU以上的应⽤.
年⽼代⼤⼩选择
响应时间优先的应⽤:年⽼代使⽤并发收集器,所以其⼤⼩需要⼩⼼设置,⼀般要考虑并发会话率和会话持续时间等⼀些参数.如果堆设置⼩了,可以会造成内存碎⽚,⾼回收频率以及应⽤暂停⽽使⽤传统的标记清除⽅式;如果堆⼤了,则需要较长的收集时间.最优化的⽅案,⼀般需要参考以下数据获得:
并发垃圾收集信息
持久代并发收集次数
传统GC信息
花在年轻代和年⽼代回收上的时间⽐例
减少年轻代和年⽼代花费的时间,⼀般会提⾼应⽤的效率
吞吐量优先的应⽤:⼀般吞吐量优先的应⽤都有⼀个很⼤的年轻代和⼀个较⼩的年⽼代.原因是,这样可以尽可能回收掉⼤部分短期对象,减少中期的对象,⽽年⽼代尽存放长期存活对象.
较⼩堆引起的碎⽚问题
因为年⽼代的并发收集器使⽤标记,清除算法,所以不会对堆进⾏压缩.当收集器回收时,他会把相邻的空间进⾏合并,这样可以分配给较⼤的对象.但是,当堆空间较⼩时,运⾏⼀段时间以后,就会出现"碎⽚",如果并发收集器不到⾜够的空间,那么并发收集器将会停⽌,然后使⽤传统的标记,清除⽅式进⾏回收.如果出现"碎⽚",可能需要进⾏如下配置:
-XX:+UseCMSCompactAtFullCollection:使⽤并发收集器时,开启对年⽼代的压缩.
-XX:CMSFullGCsBeforeCompaction=0:上⾯配置开启的情况下,这⾥设置多少次Full GC后,对年⽼代进⾏压缩
在同⼀个⼯程下,有两个类,这两个类中只有很少的变动,⽽最关健的FOR却没有⼀点变动,可是当我分
别运⾏这两个程序的时候却出现⼀个很严重的问题,⼀个程序循环的快,⼀个循环的慢.这到底是怎么回事呢~苦苦寻了半天也没有想到是为什么,因为程序改变的部分根不影响我循环的速度,可是结果却是有很⼤的差别,⼀个⼤约是在⼀分钟这内就可以循环完,可是另⼀个却需要六七分钟,这根本就不是⼀个数据理级的⿇.两个完全⼀样的循环,从代码上根本上是看不出有什么问题.不得以求助同事吧,可是同事看了也感觉很诡异,两个⼈在那订着代码⼜看了⼀个多⼩时,最后同事让我来个⼲净点的,关机重启.我到也听话,就顺着同事的意思去了,可就在关机的这个时候他突然说是不是内存的问题,我也空然想到了,还真的有可能是内存的问题,因为快的那个在我之前运⾏程序之前可给过1G的内存啊,⽽后来的这个我好像是没有设过内存啊,机器起来了,有了这个想法进去看看吧,结果正中要害,果真是慢的那个没有开内存,程序运⾏时只不过是JVM默认开的内存.我初步分析是因为内存太⼩,⽽我的程序所⽤内存⼜正好卡在JVM所开内存边上,不⾄于溢出.当程序运⾏时就得花费⼤部分时间去调⽤GC去,这样就导致了为什么相同的循环出现两种不同的效率~!
内存使⽤情况的⽅法:
public static String getMemUsage() {
long free = java.Runtime().freeMemory();
long total = java.Runtime().totalMemory();
StringBuffer buf = new StringBuffer();
buf.append("[Mem: used ").append((total-free)>>20)
.append("M free ").append(free>>20)
.append("M total ").append(total>>20).append("M]");
String();
}
google⼀下,⼤概就说JVM是这样来操作内存:
堆(Heap)和⾮堆(Non-heap)内存
按照官⽅的说法:"Java 虚拟机具有⼀个堆,堆是运⾏时数据区域,所有类实例和数组的内存均从此处分配.堆是在 Java 虚拟机启动时创建的.""在JVM中堆之外的内存称为⾮堆内存(Non-heap memory)".可以看出JVM主要管理两种类型的内存:堆和⾮堆.简单来说堆就是Java代码可及的内存,是留给开发⼈员使⽤的;⾮堆就是JVM留给⾃⼰⽤的,所以⽅法区,JVM内部处理或优化所需的内存(如JIT编译后的代码缓存),每个类结构(如运⾏时常数池,字段和⽅法数据)以及⽅法和构造⽅法的代码都在⾮堆内存中.
堆内存分配
JVM初始分配的内存由-Xms指定,默认是物理内存的1/64;JVM最⼤分配的内存由-Xmx指定,默认是物理内存的1/4.默认空余堆内存⼩于40%时,JVM就会增⼤堆直到-Xmx的最⼤限制;空余堆内存⼤于70%时, JVM会减少堆直到-Xms的最⼩限制.因此服务器⼀般设置-Xms,-Xmx相等以避免在每次GC 后调整堆的⼤⼩.
⾮堆内存分配
JVM使⽤-XX:PermSize设置⾮堆内存初始值,默认是物理内存的1/64;由XX:MaxPermSize设置最⼤⾮堆内存的⼤⼩,默认是物理内存的
1/4.
JVM内存限制(最⼤值)
⾸先JVM内存⾸先受限于实际的最⼤物理内存,假设物理内存⽆限⼤的话,JVM内存的最⼤值跟操作系统有很⼤的关系.简单的说就32位处理器虽然可控内存空间有4GB,但是具体的操作系统会给⼀个限制,这个限制⼀般是 2GB-3GB(⼀般来说Windows系统下为1.5G-2G,Linux 系统下为2G-3G),⽽64bit以上的处理器就不会有限制了
JVM内存的调优
1. Heap设定与垃圾回收Java Heap分为3个区,Young,Old和Permanent.Young保存刚实例化的对象.当该区被填满时,GC会将对象移到Old 区.Permanent区则负责保存反射对象,本⽂不讨论该区.JVM的Heap分配可以使⽤-X参数设定,
-Xms:初始Heap⼤⼩
-Xmx:java heap最⼤值
-Xmn:young generation的heap⼤⼩/年轻代的⼤⼩
2.JVM有2个GC线程
第⼀个线程负责回收Heap的Young区.
第⼆个线程在Heap不⾜时,遍历Heap,将Young 区升级为Older区.Older区的⼤⼩等于-Xmx减去-Xmn,不能将-Xms的值设的过⼤,因为第⼆个线程被迫运⾏会降低JVM的性能.
jvm调优参数3.为什么⼀些程序频繁发⽣GC?有如下原因:
l 程序内调⽤了()或().
l ⼀些中间件软件调⽤⾃⼰的GC⽅法,此时需要设置参数禁⽌这些GC.
l Java的Heap太⼩,⼀般默认的Heap值都很⼩.
l 频繁实例化对象,Release对象.此时尽量保存并重⽤对象,例如使⽤StringBuffer()和String().
如果你发现每次GC后,Heap的剩余空间会是总空间的50%,这表⽰你的Heap处于健康状态.许多Server端的Java程序每次GC后最好能有65%的剩余空间.经验之谈:
注意:
1.Server端JVM最好将-Xms和-Xmx设为相同值.为了优化GC,最好让-Xmn值约等于-Xmx的1/3[2].
2.⼀个GUI程序最好是每10到20秒间运⾏⼀次GC,每次在半秒之内完成[2].
注意:
1.增加Heap的⼤⼩虽然会降低GC的频率,但也增加了每次GC的时间.并且GC运⾏时,所有的⽤户线程将暂停,也就是GC期间,Java应⽤程序不做任何⼯作.
2.Heap⼤⼩并不决定进程的内存使⽤量.进程的内存使⽤量要⼤于-Xmx定义的值,因为Java为其他任务分配内存,例如每个线程的Stack 等.
3.Stack的设定
每个线程都有他⾃⼰的Stack.
-Xss
每个线程的Stack⼤⼩,Stack的⼤⼩限制着线程的数量.如果Stack过⼤就好导致内存溢漏.-Xss参数决定Stack⼤⼩,例如-Xss1024K.如果Stack太⼩,也会导致Stack溢漏.
4.硬件环境
硬件环境也影响GC的效率,例如机器的种类,内存,swap空间,和CPU的数量.
如果你的程序需要频繁创建很多transient对象,会导致JVM频繁GC.这种情况你可以增加机器的内存,来减少Swap空间的使⽤[2].
5.4种GC
第⼀种为单线程GC,也是默认的GC.,该GC适⽤于单CPU机器.
第⼆种为Throughput GC,是多线程的GC,适⽤于多CPU,使⽤⼤量线程的程序.第⼆种GC与第⼀种GC相似,不同在于GC在收集Young区是多线程的,但在Old区和第⼀种⼀样,仍然采⽤单线程.-XX:+UseParallelGC参数启动该GC.
第三种为Concurrent Low Pause GC,类似于第⼀种,适⽤于多CPU,并要求缩短因GC造成程序停滞的时间.这种GC可以在Old区的回收同时,运⾏应⽤程序.-XX:+UseConcMarkSweepGC参数启动该GC.
第四种为Incremental Low Pause GC,适⽤于要求缩短因GC造成程序停滞的时间.这种GC可以在Young区回收的同时,回收⼀部分Old区对象.-Xincgc参数启动该GC.
6. GC如何运作?
分代收集,在新⽣代区频繁发⽣,在⽼年区较少发⽣,永久区基本不发⽣
7.GC的四⼤算法
1、复制算法
效率⾼,不会产⽣内存碎⽚,但需要双倍空间,在新⽣代区中使⽤
2、标记清除算法
⽆需双倍空间,但会产⽣内存碎⽚,但需要进⾏两次扫描,在⽼年代区中使⽤
3.标记压缩算法
⽆需双倍空间,不会产⽣内存碎⽚,但移动对象需要时间,在⽼年代中使⽤
4.标记清除压缩算法
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论