jvm运行时分析

官方手册:
http://docs.oracle.com/javase/7/docs/     ---->
http://docs.oracle.com/javase/7/docs/technotes/tools/solaris/java.html   java命令的各种选项的说明

参考书籍:

《深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)》

首先说下JVM的内存堆结构,看下图:

主要由 方法区Permanent Generation + 新生代Eden + 新生代幸存区S0和S1 + 老年代Old Generation;
大部分新生成的对象都放在Eden中,当Eden内存不够用时,触发Young GC,这时,会将Eden中不能被释放的对象以及S0中幸存的对象,都Copy到S1中,并且将经历过几次Young GC还幸存的新生代对象,放入到Old Generation中,然后释放Eden和S0;

所以S0和S1是来回切换使用的,保存新生代中还不能被释放的对象,所以S0和S1总有一个会是空的,当然在发生Youg GC时,对象正在COPY时会是二者都有数据;
如果经历几次Young GC时新生代还是满的,还不能够接收Eden中过来的幸存对象,就会抛出java.lang.OutOfMemorryError:java heap space;

如果在进行Youg GC时,发现S0不够用时,则直接将对象放入Old Generation中,这时如果Old Generation内存也不够时,则触发Full GC,Full GC后如果Old Generation还是满的,就抛出内存溢出异常:
java.lang.OutOfMemorryError:java heap space;

所以,假设有一个永不销毁的对象,其经历的过程如下:首先在创建时放入Eden,当某个时刻Eden满了时,通过Young GC放入S0或者S1,其在S0或者S1经历过几次Youg GC后,放入到Old generation中,当Old Generation满了的时候,发生Full GC.

这里有点需要注意,代码区(方法区),并不属于堆空间,他是一个单独的空间,其中保存有虚拟机自己的静态数据,以及加载的Class类级别静态对象,如class本身,method,field等,当然如果这部分空间不足时,一样会触发Full GC.而且如果GC之后还是满的,就会抛出PermGen Space异常

上面说到了堆和方法区,接下来我们看下完整的JVM内存结构:

之前说了堆结构和代码区Permanent Space,顺着这个内存结构图,说下Code Generation,JVM自己内部使用的一块区域,用来编译和保存本地代码(native code),基本不会导致内存异常。如果该操作没有足够的空间,JVM可能会导致崩溃

Socket Buffers:用来做网络通信的缓冲区,分为发送去和接收区,需要在java代码中控制它,所以外部无法配置。这里如果满了的话,会导致IOException: Too many open files 。

Thread JVM Stack:java的线程栈,java分配一个对象时,对象的具体内容在堆中,而对象的引用则位于栈中,也就是这里。而且方法的局部变量以及函数地址的调入和调出,都存放在这里,所以,JAVA的一个对象,有两部分,对象本身的值在堆中,而引用则在栈中。当栈空间不够时,比如递归层次太深,就会导致java.lang.StackOverflowError异常
Direct Memory Space:他可以让开发人员映射内存到java Object Heap外

JNI Code :JNI code本身使用的内存非常小。

JNI allocate memory:JNI 程序本身也需要分配内存。

Garbage Collection:其实GC也是需要内存的,gc线程的消耗以及存放GC所缓存的信息。

所以,java进程实际占用并不等于堆内存的大小,很显然还有栈呀代码区呀什么之类的内存的大小。

再看一个列子,一个进程,设置的启动参数中,堆的最大内存指定为30G,而通过TOP命令,查看的内存使用情况为:

显然,这里的虚拟内存大小变成了38G,远远超过指定的堆的大小30G,究其原因,一是,进程占用的内存除了堆,还有栈空间之类的,就是上面标红的一部分,二是,虚拟内存表示java像操作系统申请了38G,但是实际使用只有27G。在操作系统级别,内存是按页分配的,而且,如果你申请了空间,不访问它,那么虚拟内存使用大小是你申请的大小,而RES却是0,当你访问时,如果物理内存不足,就有可能导致要访问的内存页不在物理内存里,会发生缺页中断,发生CPU的上下文切换,性能会下降,而这时RES才会增大。而且从经验来看Xms和Xmx是告诉JAVA,我实际要使用的堆的最大值是多少,也就是RES是多少,也就是说我实际有可能要放28G的对象进来,而我们知道JVM的堆空间,S0和S1是切换的,所以,java实际需要向操作系统申请的空间肯定大于28G,但是实际进程使用的却只有27G,这就是为什么上图显示RES为27G而VIRT是38G。

jstat的总体使用参数说明

Option Displays…
class class loader的行为统计。Statistics on the behavior of the class loader.
compiler HotSpt JIT编译器行为统计。Statistics of the behavior of the HotSpot Just-in-Time compiler.
gc 垃圾回收堆的行为统计。Statistics of the behavior of the garbage collected heap.
gccapacity 各个垃圾回收代容量(young,old,perm)和他们相应的空间统计。Statistics of the capacities of the generations and their corresponding spaces.
gccause 垃圾收集统计概述(同-gcutil),附加最近两次垃圾回收事件的原因。Summary of garbage collection statistics (same as -gcutil), with the cause of the last and
current (if applicable) garbage collection events.
gcnew 新生代行为统计。Statistics of the behavior of the new generation.
gcnewcapacity 新生代与其相应的内存空间的统计。Statistics of the sizes of the new generations and its corresponding spaces.
gcold 年老代和永生代行为统计。Statistics of the behavior of the old and permanent generations.
gcoldcapacity 年老代行为统计。Statistics of the sizes of the old generation.
gcpermcapacity 永生代行为统计。Statistics of the sizes of the permanent generation.
gcutil 垃圾回收统计概述。Summary of garbage collection statistics.
printcompilation HotSpot编译方法统计。HotSpot compilation method statistics.

-h 
n每隔
n个样本 (行),
n是正整数,

缺省为0,代表只有第一行为列头。
-t 
n第一行输出为时间戳,

它表示自从目标JVM启动以来逝去的时间,以秒为单位。

如何查看JVM的性能呢?现在给出实际的列子:

1、查看java命令启动参数

jinfo 20611

Attaching to process ID 20611, please wait...

Debugger attached successfully.

Server compiler detected.

JVM version is 19.1-b02

Java System Properties:

java.runtime.name = Java(TM) SE Runtime Environment

sun.boot.library.path = /usr/lib/jvm/java-1.6.0-sun-1.6.0.24.x86_64/jre/lib/amd64

java.vm.version = 19.1-b02

java.vm.vendor = Sun Microsystems Inc.

java.vendor.url = http://java.sun.com/

path.separator = :

java.vm.name = Java HotSpot(TM) 64-Bit Server VM

file.encoding.pkg = sun.io

sun.java.launcher = SUN_STANDARD

user.country = US

sun.os.patch.level = unknown

java.vm.specification.name = Java Virtual Machine Specification

user.dir = /mezi/dps/local/investopedia-market-service

java.runtime.version = 1.6.0_24-b07

java.awt.graphicsenv = sun.awt.X11GraphicsEnvironment

java.endorsed.dirs = /usr/lib/jvm/java-1.6.0-sun-1.6.0.24.x86_64/jre/lib/endorsed

os.arch = amd64

java.io.tmpdir = /tmp

line.separator =

java.vm.specification.vendor = Sun Microsystems Inc.

os.name = Linux

sun.jnu.encoding = UTF-8

java.library.path = /usr/lib/jvm/java-1.6.0-sun-1.6.0.24.x86_64/jre/lib/amd64/server:/usr/lib/jvm/java-1.6.0-sun-1.6.0.24.x86_64/jre/lib/amd64:/usr/lib/jvm/java-1.6.0-sun-1.6.0.24.x86_64/jre/../lib/amd64:/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib

java.specification.name = Java Platform API Specification

java.class.version = 50.0

sun.management.compiler = HotSpot 64-Bit Server Compiler

os.version = 2.6.18-348.12.1.el5

user.home = /home/mmdps

user.timezone = UTC

java.awt.printerjob = sun.print.PSPrinterJob

file.encoding = UTF-8

java.specification.version = 1.6

java.class.path = :libs/aopalliance.jar:libs/axiom-api-1.2.13.jar:libs/axiom-impl-1.2.13.jar:libs/axis2-adb-1.6.2.jar:libs/axis2-kernel-1.6.2.jar:libs/axis2-transport-http-1.6.2.jar:libs/axis2-transport-local-1.6.2.jar:libs/axis2-xmlbeans-1.6.2.jar:libs/bonecp-0.7.1.RELEASE.jar:libs/commons-codec-1.3.jar:libs/commons-httpclient-3.1.jar:libs/commons-lang-2.5.jar:libs/ehcache-2.7.1.jar:libs/google-collections-1.0.jar:libs/gson-2.2.4.jar:libs/guice-3.0.jar:libs/httpcore-4.0.jar:libs/javax.inject.jar:libs/jetty-client-8.1.10.v20130312.jar:libs/jetty-continuation-8.1.10.v20130312.jar:libs/jetty-http-8.1.10.v20130312.jar:libs/jetty-io-8.1.10.v20130312.jar:libs/jetty-security-8.1.10.v20130312.jar:libs/jetty-server-8.1.10.v20130312.jar:libs/jetty-servlet-8.1.10.v20130312.jar:libs/jetty-util-8.1.10.v20130312.jar:libs/jetty-xml-8.1.10.v20130312.jar:libs/json-rpc-1.0.jar:libs/log4j-1.2.15.jar:libs/mail-1.4.jar:libs/mockito-all-1.9.0.jar:libs/mysql-connector-java-5.1.7-bin.jar:libs/neethi-3.0.2.jar:libs/quartz.jar:libs/servlet-api-3.0.jar:libs/slf4j-api-1.7.5.jar:libs/slf4j-log4j12-1.7.5.jar:libs/start.jar:libs/wsdl4j-1.6.2.jar:libs/xmlbeans-2.3.0.jar:libs/XmlSchema-1.4.7.jar:properties:resources

user.name = mmdps

java.vm.specification.version = 1.0

java.home = /usr/lib/jvm/java-1.6.0-sun-1.6.0.24.x86_64/jre

sun.arch.data.model = 64

user.language = en

java.specification.vendor = Sun Microsystems Inc.

java.vm.info = mixed mode

java.version = 1.6.0_24

java.ext.dirs = /usr/lib/jvm/java-1.6.0-sun-1.6.0.24.x86_64/jre/lib/ext:/usr/java/packages/lib/ext

sun.boot.class.path = /usr/lib/jvm/java-1.6.0-sun-1.6.0.24.x86_64/jre/lib/resources.jar:/usr/lib/jvm/java-1.6.0-sun-1.6.0.24.x86_64/jre/lib/rt.jar:/usr/lib/jvm/java-1.6.0-sun-1.6.0.24.x86_64/jre/lib/sunrsasign.jar:/usr/lib/jvm/java-1.6.0-sun-1.6.0.24.x86_64/jre/lib/jsse.jar:/usr/lib/jvm/java-1.6.0-sun-1.6.0.24.x86_64/jre/lib/jce.jar:/usr/lib/jvm/java-1.6.0-sun-1.6.0.24.x86_64/jre/lib/charsets.jar:/usr/lib/jvm/java-1.6.0-sun-1.6.0.24.x86_64/jre/lib/modules/jdk.boot.jar:/usr/lib/jvm/java-1.6.0-sun-1.6.0.24.x86_64/jre/classes

java.vendor = Sun Microsystems Inc.

file.separator = /

java.vendor.url.bug = http://java.sun.com/cgi-bin/bugreport.cgi

sun.io.unicode.encoding = UnicodeLittle

sun.cpu.endian = little

sun.cpu.isalist =

VM Flags:

-Xms2000m -Xmx8000m

2、 jstat -gc pid 查看垃圾回收统计

jstat -gc 50206 500 10

列名 描述
S0C 当前survivor space 0容量。Current survivor space 0 capacity (KB).
S1C survivor space 1容量。Current survivor space 1 capacity (KB).
S0U Survivor space 0 利用情况。Survivor space 0 utilization (KB).
S1U Survivor space 1 利用情况。Survivor space 1 utilization (KB).
EC 当前新生代eden空间容量。Current eden space capacity (KB).
EU 新生代eden空间利用情况。Eden space utilization (KB).
OC 当前年老代空间容量。Current old space capacity (KB).
OU 年老代利用情况。Old space utilization (KB).
PC 当前永生代空间容量。Current permanent space capacity (KB).
PU 永生代空间利用情况。Permanent space utilization (KB).
YGC 新生代GC事件次数。 Number of young generation GC Events.
YGCT 新生代GC耗时。Young generation garbage collection time.
FGC full GC次数。Number of full GC events.
FGCT full gc耗时。Full garbage collection time.
GCT 总GC耗时。Total garbage collection time.

3、GC内存空间使用统计

jstat -gccapacity 20611 500 5

列名 描述
NGCMN 最小新生代容量。Minimum new generation capacity (KB).
NGCMX 最大新生代容量。Maximum new generation capacity (KB).
NGC 当前新生代容量。Current new generation capacity (KB).
S0C 当前新生代survivor 0区容量。Current survivor space 0 capacity (KB).
S1C 当前新生代survivor 1区容量。Current survivor space 1 capacity (KB).
EC 当前新生代eden空间容量。Current eden space capacity (KB).
OGCMN 最小年老代容量。Minimum old generation capacity (KB).
OGCMX 最大年老代容量。Maximum old generation capacity (KB).
OGC 当前年老代容量。Current old generation capacity (KB).
OC 当前年老代空间容量。Current old space capacity (KB).
PGCMN 最小永生代容量。Minimum permanent generation capacity (KB).
PGCMX 最大永生代容量。Maximum Permanent generation capacity (KB).
PGC 当前新生成的永生代容量。Current Permanent generation capacity (KB).
PC 当前永生代空间容量。Current Permanent space capacity (KB).
YGC 新生代GC次数。Number of Young generation GC Events.
FGC Full GC次数。Number of Full GC Events.

4、GC内存空间各区使用比例
jstat -gcutil 20611 500 5

列名 描述
S0 survivor 0区利用率。
Survivor space 0 utilization as a percentage of
the space’s current capacity.
S1 survivor 1区利用率。
Survivor space 1 utilization as a percentage of
the space’s current capacity.
E eden区利用率。
Eden space utilization as a percentage of
the space’s current capacity.
O 年老代空间利用率。
Old space utilization as a percentage of
the space’s current capacity.
P 永生代空间利用率。Permanent space utilization as a percentage of
the space’s current capacity.
YGC young gc次数。
Number of young generation GC events.
YGCT young gc耗时。
Young generation garbage collection time.
FGC full gc次数。
Number of full GC events.
FGCT full gc耗时。
Full garbage collection time.
GCT GC总耗时。
Total garbage collection time.

5、GC内存空间的GC原因
与-gcutil相同,多两列,一个是最后一次GC原因,一个是本次GC原因
 jstat -gccause 20611 500 5

列名 描述
LGCC 上次GC原因。Cause of last Garbage Collection.
GCC 本次GC原因。Cause of current Garbage Collection.

6、新生代使用情况
 jstat -gcnew 20611 500 5

列名 描述
S0C 当前survivor 0区容量。Current
survivor space 0 capacity (KB).
S1C 当前survivor 1区容量。Current
survivor space 1 capacity (KB).
S0U 当前survivor 0区利用情况。
Survivor space 0 utilization (KB).
S1U 当前survivor 1区利用情况。
Survivor space 1 utilization (KB).
TT 阀值, 用于控制对象在新生代存活的次数。
Tenuring threshold.
MTT 阀值, 用于控制对象在新生代存活的最大次数。Maximum tenuring threshold.
DSS 期望存活大小。
Desired survivor size (KB).
EC 当前eden空间容量。Current eden space capacity (KB).
EU eden空间利用情况。
Eden space utilization (KB).
YGC 年轻代gc次数。Number of young generation GC events.
YGCT 年轻代GC耗时。
Young generation garbage collection time.

note: 若某个age上的survivor space对象的大小如果超过Desired survivor size,则重新计算tenuring threshold,以age和MaxTenuringThreshold的最小值为准

7、新生代空间统计

jstat -gcnewcapacity 20611 500 5

列名 描述
NGCMN 最小新生代容量。Minimum new generation capacity (KB).
NGCMX 最大新生代容量。Maximum new generation capacity (KB).
NGC 当前新生代容量。Current new generation capacity (KB).
S0CMX 最大survivor 0区容量。Maximum survivor space 0 capacity (KB).
S0C 当前survivor 0区容量。Current survivor space 0 capacity (KB).
S1CMX 最大survivor 1区容量。Maximum
survivor space 1 capacity (KB).
S1C 当前survivor 1区容量。Current survivor space 1 capacity (KB).
ECMX 最大eden区容量。Maximum eden space capacity (KB).
EC 当前eden区容量。Current eden space capacity (KB).
YGC young gc次数。
Number of young generation GC events.
FGC full gc次数。Number of Full GC Events.

8、年老代使用情况

jstat -gcold 20611 500 5

列名 描述
PC 当前永久代空间容量。Current permanent space capacity (KB).
PU 永久代空间利用情况。Permanent space utilization (KB).
OC 当前年老代空间容量。Current old space capacity (KB).
OU 年老代空间利用情况。
old space utilization (KB).
YGC young gc次数。
Number of young generation GC events.
FGC full gc次数。Number of full GC events.
FGCT full gc耗时。
Full garbage collection time.
GCT gc总耗时。
Total garbage collection time.

9、年老代空间容量

jstat -gcoldcapacity 20611 500 5

列名 描述
OGCMN 最小年老代容量。Minimum
old generation capacity (KB).
OGCMX 最大年老代容量。Maximum
old generation capacity (KB).
OGC 当前年老代容量。Current
old generation capacity (KB).
OC 当前年老代空间容量。Current
old space capacity (KB).
YGC young gc次数。
Number of young generation GC events.
FGC full gc次数。
Number of full GC events.
FGCT full gc耗时。Full garbage collection time.
GCT 总GC耗时。
Total garbage collection time.

10、永生代统计

jstat -gcpermcapacity 20611 500 5

列名 描述
PGCMN Minimum permanent generation capacity (KB).
PGCMX Maximum permanent generation capacity (KB).
PGC Current permanent generation capacity (KB).
PC Current permanent space capacity (KB).
YGC Number of young generation GC events.
FGC Number of full GC events.
FGCT Full garbage collection time.
GCT Total garbage collection time.

11、编译统计

jstat -printcompilation 20611 500 5

列名 描述
Compiled 执行的编译任务次数
Size Number of bytes of bytecode for the method.
Type 编译类型。Compilation type.
Method 类名和方法名。类名使用”/”代替了原命名空间符号”.”

12、类加载情况

jstat -class 20611 500 5

列名 描述
Loaded 已加载的类个数。
Bytes 已加载类占用字节数(KB为单位)。
Unloaded 卸载的类个数。
Bytes 卸载的类占用字节数(KB为单位)。
Time 加载和卸载操作花费的时间。

13、栈大小的调整

jinfo flag 
ThreadStackSize 
20611
 :-XX:ThreadStackSize=1024

按照以上这些数据,我们做下内存分布的分析

先看持久代,参数设置为:XX:PermSize 最小值,XX:MaxpermSize最大值
使用 jinfo -flag PermSize 20611  + jinfo -flag MaxPermSize 20611 看到值分别为:

-XX:PermSize=21757952 -XX:MaxPermSize=85983232,因为上面的进程,我们没配置它,所以这两个值就是默认值,一个是20.75M,一个是82M,

这个与
 jstat -gcpermcapacity 20611 500 5命令中的  
PGCMN = 
21248.0 KB 和  
PGCMX= 
83968.0 KB是相吻合的,同时我们看到当前容量为
31M,

所以,这个总容量是没太大问题的,但是这里会发生在GC之后内存收缩情况,
所以我们一般都设置成 XX:PermSize=XX:MaxPermSize

实验1(持久代),我们用参数配置后再来启动它,
 -XX:PermSize=50M  -XX:MaxPermSize=100M,使用 jstat -gcpermcapacity命令后发现PGCMN=51200
PGCMX=102400,PGC=51200,所以,和我们期望的是一样的,但是如果想看我们实际占用了多少呢?通过jstat -gc 19539  命令,可以发现

PC=51200,PU=29174.4,说明我们实际是用了29M

反过来,因为我们知道我们的进程需要占用29M的空间,当我们把 -XX:PermSize=10M -XX:MaxPermSize=10M配置成最多使用10M时,启动进程就会发现报了如下错误:

Exception in thread "main" java.lang.OutOfMemoryError: PermGen space

看下新生代区,一共有这几个参数可以影响到其大小: 
指定年轻代的大小(Eden+S0+S1);
-XX:NewSize设置年轻代初始化值大小;
-XX:MaxNewSize设置年轻代最大值,

-XX:NewRatio年轻代与年老代的比值,
Xms=Xmx并且设置了Xmn的情况下,该参数不需要进行设置;
-XX:SurvivorRatio设置
Survivor

Eden
之间的比值,如果设置为8,则表示
一个Surivior(S0)为1,Eden为8,所以,S0占年轻代的1/10,S1占1/10,Eden占8/10

先使用jinfo -falg看下这些值的默认配置:-XX:NewSize=1310720  -XX:MaxNewSize=18446744073709486080(无限制) -XX:NewRatio=2 -XX:SurvivorRatio=8
当我使用java -server -
Xmn3000M
 -XX:SurvivorRatio=8 -XX:NewSize=3000M -XX:MaxNewSize=3000M -XX:PermSize=500M -XX:MaxPermSize=500M 
-Xms2000m
 -Xmx8000m该参数时启动会报错,
Error occurred during initialization of VM ,Too small initial heap for new size specified
,原因在于-Xms指定初始化堆大小为2000M,而最小新生代
-Xmn3000
都比该值大,这个是不允许的,所以,

调整后的参数为:java -server -Xmn3000M -XX:SurvivorRatio=8 -XX:NewSize=3000M -XX:MaxNewSize=3000M -XX:PermSize=500M -XX:MaxPermSize=500M -Xms8000m -Xmx8000m

使用jstat -gcnewcapacity 26111命令发现,最小最大新生代的大小
确实
都是3000M,但奇怪的是S0\S1\Eden的最大值也都是3000M,Eden实际容量是2400M,

这说明这种情况下
-
XX:SurvivorRatio=8这个参数不起作用了。

而一般我们配置
XX:SurvivorRatio=1从而使
新生代Eden=S0=S1,并且Xmn设置新生代的大小

调整后的参数为:-Xmn3000M -XX:SurvivorRatio=1 -XX:PermSize=500M -XX:MaxPermSize=500M -Xms8000m -Xmx8000m

这时候再使用gcnewcapacity就会发现:NGCMN=NGCMX=NGC=3000M,lS0C=S1C=EC=1024000,跟我们预期的完全一样!
但是运行一段时间以后,发现值稍微有了一些变化,S0C=1024000,S1C=836224,EC=1360512,就是EC变大了,而S1变小了,至于为什么,不得而已???

看下老年区
老年区没得设置,因为其空间大小就是堆的总空间减去年轻代的空间


其他的一些设置:

-XX:+UseConcMarkSweepGC 使用CMS模式进行垃圾回收,该机制的特点是并发收集、低停顿,但同时,也会产生一些碎片和浮动垃圾,因为CMS并发清理阶段用户线程还在运行着,伴随程序的运行自然还会有新的垃这一部分垃圾出现在标记过程之后,CMS无法在本次收集中处理掉它们,只好留待下一次GC时再将其清理掉,这部分就是浮动垃圾。
-XX:+UseCMSCompactAtFullCollection,在FULL GC的时候, 对年老代的压缩。由于启动了CMS机制进行垃圾收集,其会产生碎片,所以圾不断产生,所以该选择需要配合上面这个选择,CMS收集器一起使用

-XX:CMSInitiatingOccupancyFraction=70 使用cms作为垃圾回收,使用70%后开始CMS收集。为了保证不出现promotion failed(见下面介绍)错误,该值的设置需要满足以下公式CMSInitiatingOccupancyFraction计算公式

CMSInitiatingOccupancyFraction值与Xmn的关系公式

上面介绍了promontion faild产生的原因是EDEN空间不足的情况下将EDEN与From survivor中的存活对象存入To survivor区时,To survivor区的空间不足,再次晋升到old gen区,而old gen区内存也不够的情况下产生了promontion faild从而导致full gc.那可以推断出:eden+from survivor < old gen区剩余内存时,不会出现promontion faild的情况,即:
(Xmx-Xmn)*(1-CMSInitiatingOccupancyFraction/100)>=(Xmn-Xmn/(SurvivorRatior+2))  进而推断出:

CMSInitiatingOccupancyFraction <=((Xmx-Xmn)-(Xmn-Xmn/(SurvivorRatior+2)))/(Xmx-Xmn)*100

-XX:+UseParNewGC 设置年轻代为并行收集   可与CMS收集同时使用
JDK5.0以上,JVM会根据系统配置自行设置,所以无需再设置此值
-XX:ParallelGCThreads 并行收集器的线程数   此值最好配置与处理器数目相等 同样适用于CMS

网上一个很NB的配置参考:

$JAVA_ARGS
.=
"
-Dresin.home=$SERVER_ROOT
-server
-Xmx3000M
-Xms3000M
-Xmn600M
-XX:PermSize=500M
-XX:MaxPermSize=500M
-Xss256K
-XX:+DisableExplicitGC
-XX:SurvivorRatio=1
-XX:+UseConcMarkSweepGC
-XX:+UseParNewGC
-XX:+CMSParallelRemarkEnabled
-XX:+UseCMSCompactAtFullCollection
-XX:CMSFullGCsBeforeCompaction=0
-XX:+CMSClassUnloadingEnabled
-XX:LargePageSizeInBytes=128M
-XX:+UseFastAccessorMethods
-XX:+UseCMSInitiatingOccupancyOnly
-XX:CMSInitiatingOccupancyFraction=70
-XX:SoftRefLRUPolicyMSPerMB=0
-XX:+PrintClassHistogram
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+PrintHeapAtGC
-Xloggc:log/gc.log
";

64位jdk参考设置,年老代涨得很慢,CMS执行频率变小,CMS没有停滞,也不会有promotion failed问题,内存回收得很干净

很有用的一个各参数说明:

JVM参数的含义 实例见实例分析
参数名称 含义 默认值  
-Xms 初始堆大小 物理内存的1/64(<1GB) 默认(MinHeapFreeRatio参数可以调整)空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制.
-Xmx 最大堆大小 物理内存的1/4(<1GB) 默认(MaxHeapFreeRatio参数可以调整)空余堆内存大于70%时,JVM会减少堆直到 -Xms的最小限制
-Xmn 年轻代大小(1.4or lator)   注意:此处的大小是(eden+ 2 survivor space).与jmap -heap中显示的New gen是不同的。 整个堆大小=年轻代大小 + 年老代大小 + 持久代大小. 增大年轻代后,将会减小年老代大小.此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8
-XX:NewSize 设置年轻代大小(for 1.3/1.4)    
-XX:MaxNewSize 年轻代最大值(for 1.3/1.4)    
-XX:PermSize 设置持久代(perm gen)初始值 物理内存的1/64  
-XX:MaxPermSize 设置持久代最大值 物理内存的1/4  
-Xss 每个线程的堆栈大小   JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K.更具应用的线程所需内存大小进行 调整.在相同物理内存下,减小这个值能生成更多的线程.但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右 一般小的应用, 如果栈不是很深, 应该是128k够用的 大的应用建议使用256k。这个选项对性能影响比较大,需要严格的测试。(校长) 和threadstacksize选项解释很类似,官方文档似乎没有解释,在论坛中有这样一句话:"” -Xss is translated in a VM flag named ThreadStackSize” 一般设置这个值就可以了。
-XX:ThreadStackSize Thread Stack Size   (0 means use default stack size) [Sparc: 512; Solaris x86: 320 (was 256 prior in 5.0 and earlier); Sparc 64 bit: 1024; Linux amd64: 1024 (was 0 in 5.0 and earlier); all others 0.]
-XX:NewRatio 年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)   -XX:NewRatio=4表示年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5 Xms=Xmx并且设置了Xmn的情况下,该参数不需要进行设置。
-XX:SurvivorRatio Eden区与Survivor区的大小比值   设置为8,则两个Survivor区与一个Eden区的比值为2:8,一个Survivor区占整个年轻代的1/10
-XX:LargePageSizeInBytes 内存页的大小不可设置过大, 会影响Perm的大小   =128m
-XX:+UseFastAccessorMethods 原始类型的快速优化    
-XX:+DisableExplicitGC 关闭System.gc()   这个参数需要严格的测试
-XX:MaxTenuringThreshold 垃圾最大年龄   如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代. 对于年老代比较多的应用,可以提高效率.如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活 时间,增加在年轻代即被回收的概率 该参数只有在串行GC时才有效.
-XX:+AggressiveOpts 加快编译    
-XX:+UseBiasedLocking 锁机制的性能改善    
-Xnoclassgc 禁用垃圾回收    
-XX:SoftRefLRUPolicyMSPerMB 每兆堆空闲空间中SoftReference的存活时间 1s softly reachable objects will remain alive for some amount of time after the last time they were referenced. The default value is one second of lifetime per free megabyte in the heap
-XX:PretenureSizeThreshold 对象超过多大是直接在旧生代分配 0 单位字节 新生代采用Parallel Scavenge GC时无效 另一种直接在旧生代分配的情况是大的数组对象,且数组中无外部引用对象.
-XX:TLABWasteTargetPercent TLAB占eden区的百分比 1%  
-XX:+CollectGen0First FullGC时是否先YGC false  
并行收集器相关参数
-XX:+UseParallelGC Full GC采用parallel MSC (此项待验证)   选择垃圾收集器为并行收集器.此配置仅对年轻代有效.即上述配置下,年轻代使用并发收集,而年老代仍旧使用串行收集.(此项待验证)
-XX:+UseParNewGC 设置年轻代为并行收集   可与CMS收集同时使用 JDK5.0以上,JVM会根据系统配置自行设置,所以无需再设置此值
-XX:ParallelGCThreads 并行收集器的线程数   此值最好配置与处理器数目相等 同样适用于CMS
-XX:+UseParallelOldGC 年老代垃圾收集方式为并行收集(Parallel Compacting)   这个是JAVA 6出现的参数选项
-XX:MaxGCPauseMillis 每次年轻代垃圾回收的最长时间(最大暂停时间)   如果无法满足此时间,JVM会自动调整年轻代大小,以满足此值.
-XX:+UseAdaptiveSizePolicy 自动选择年轻代区大小和相应的Survivor区比例   设置此选项后,并行收集器会自动选择年轻代区大小和相应的Survivor区比例,以达到目标系统规定的最低相应时间或者收集频率等,此值建议使用并行收集器时,一直打开.
-XX:GCTimeRatio 设置垃圾回收时间占程序运行时间的百分比   公式为1/(1+n)
-XX:+ScavengeBeforeFullGC Full GC前调用YGC true Do young generation GC prior to a full GC. (Introduced in 1.4.1.)
CMS相关参数
-XX:+UseConcMarkSweepGC 使用CMS内存收集   测试中配置这个以后,-XX:NewRatio=4的配置失效了,原因不明.所以,此时年轻代大小最好用-Xmn设置.???
-XX:+AggressiveHeap     试图是使用大量的物理内存 长时间大内存使用的优化,能检查计算资源(内存, 处理器数量) 至少需要256MB内存 大量的CPU/内存, (在1.4.1在4CPU的机器上已经显示有提升)
-XX:CMSFullGCsBeforeCompaction 多少次后进行内存压缩   由于并发收集器不对内存空间进行压缩,整理,所以运行一段时间以后会产生"碎片",使得运行效率降低.此值设置运行多少次GC以后对内存空间进行压缩,整理.
-XX:+CMSParallelRemarkEnabled 降低标记停顿    
-XX+UseCMSCompactAtFullCollection 在FULL GC的时候, 对年老代的压缩   CMS是不会移动内存的, 因此, 这个非常容易产生碎片, 导致内存不够用, 因此, 内存的压缩这个时候就会被启用。 增加这个参数是个好习惯。 可能会影响性能,但是可以消除碎片
-XX:+UseCMSInitiatingOccupancyOnly 使用手动定义初始化定义开始CMS收集   禁止hostspot自行触发CMS GC
-XX:CMSInitiatingOccupancyFraction=70 使用cms作为垃圾回收 使用70%后开始CMS收集 92 为了保证不出现promotion failed(见下面介绍)错误,该值的设置需要满足以下公式CMSInitiatingOccupancyFraction计算公式
-XX:CMSInitiatingPermOccupancyFraction 设置Perm Gen使用到达多少比率时触发 92  
-XX:+CMSIncrementalMode 设置为增量模式   用于单CPU情况
-XX:+CMSClassUnloadingEnabled      
辅助信息
-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     可与-XX:+PrintGC -XX:+PrintGCDetails混合使用 输出形式:11.851: [GC 98328K->93620K(130112K), 0.0082960 secs]
-XX:+PrintGCApplicationStoppedTime 打印垃圾回收期间程序暂停的时间.可与上面混合使用   输出形式:Total time for which application threads were stopped: 0.0468229 seconds
-XX:+PrintGCApplicationConcurrentTime 打印每次垃圾回收前,程序未中断的执行时间.可与上面混合使用   输出形式:Application time: 0.5291524 seconds
-XX:+PrintHeapAtGC 打印GC前后的详细堆栈信息    
-Xloggc:filename 把相关日志信息记录到文件以便分析. 与上面几个配合使用    
-XX:+PrintClassHistogram garbage collects before printing the histogram.    
-XX:+PrintTLAB 查看TLAB空间的使用情况    
XX:+PrintTenuringDistribution 查看每次minor GC后新的存活周期的阈值   Desired survivor size 1048576 bytes, new threshold 7 (max 15) new threshold 7即标识新的存活周期的阈值为7。
GC性能方面的考虑 对于GC的性能主要有2个方面的指标:吞吐量throughput(工作时间不算gc的时间占总的时间比)和暂停pause(gc发生时app对外显示的无法响应)。 1. Total Heap 默认情况下,vm会增加/减少heap大小以维持free space在整个vm中占的比例,这个比例由MinHeapFreeRatio和MaxHeapFreeRatio指定。 一般而言,server端的app会有以下规则:
  • 对vm分配尽可能多的memory;
  • 将Xms和Xmx设为一样的值。如果虚拟机启动时设置使用的内存比较小,这个时候又需要初始化很多对象,虚拟机就必须重复地增加内存。
  • 处理器核数增加,内存也跟着增大。
2. The Young Generation 另外一个对于app流畅性运行影响的因素是young generation的大小。young generation越大,minor collection越少;但是在固定heap size情况下,更大的young generation就意味着小的tenured generation,就意味着更多的major collection(major collection会引发minor collection)。 NewRatio反映的是young和tenured generation的大小比例。NewSize和MaxNewSize反映的是young generation大小的下限和上限,将这两个值设为一样就固定了young generation的大小(同Xms和Xmx设为一样)。 如果希望,SurvivorRatio也可以优化survivor的大小,不过这对于性能的影响不是很大。SurvivorRatio是eden和survior大小比例。 一般而言,server端的app会有以下规则:
  • 首先决定能分配给vm的最大的heap size,然后设定最佳的young generation的大小;
  • 如果heap size固定后,增加young generation的大小意味着减小tenured generation大小。让tenured generation在任何时候够大,能够容纳所有live的data(留10%-20%的空余)。
经验&&规则
  1. 年轻代大小选择
  2. 响应时间优先的应用:尽可能设大,直到接近系统的最低响应时间限制(根据实际情况选择).在此种情况下,年轻代收集发生的频率也是最小的.同时,减少到达年老代的对象.
  3. 吞吐量优先的应用:尽可能的设置大,可能到达Gbit的程度.因为对响应时间没有要求,垃圾收集可以并行进行,一般适合8CPU以上的应用.
  4. 避免设置过小.当新生代设置过小时会导致:1.YGC次数更加频繁 2.可能导致YGC对象直接进入旧生代,如果此时旧生代满了,会触发FGC.
  5. 年老代大小选择
响应时间优先的应用:年老代使用并发收集器,所以其大小需要小心设置,一般要考虑并发会话率和会话持续时间等一些参数.如果堆设置小了,可以会造成内存碎 片,高回收频率以及应用暂停而使用传统的标记清除方式;如果堆大了,则需要较长的收集时间.最优化的方案,一般需要参考以下数据获得: 并发垃圾收集信息、持久代并发收集次数、传统GC信息、花在年轻代和年老代回收上的时间比例。
  1. 吞吐量优先的应用:一般吞吐量优先的应用都有一个很大的年轻代和一个较小的年老代.原因是,这样可以尽可能回收掉大部分短期对象,减少中期的对象,而年老代尽存放长期存活对象.
  2. 较小堆引起的碎片问题 因为年老代的并发收集器使用标记,清除算法,所以不会对堆进行压缩.当收集器回收时,他会把相邻的空间进行合并,这样可以分配给较大的对象.但是,当堆空间较小时,运行一段时间以后,就会出现"碎片",如果并发收集器找不到足够的空间,那么并发收集器将会停止,然后使用传统的标记,清除方式进行回收.如果出现"碎片",可能需要进行如下配置: -XX:+UseCMSCompactAtFullCollection:使用并发收集器时,开启对年老代的压缩. -XX:CMSFullGCsBeforeCompaction=0:上面配置开启的情况下,这里设置多少次Full GC后,对年老代进行压缩
  3. 用64位操作系统,Linux下64位的jdk比32位jdk要慢一些,但是吃得内存更多,吞吐量更大
  4. XMX和XMS设置一样大,MaxPermSize和MinPermSize设置一样大,这样可以减轻伸缩堆大小带来的压力
  5. 使用CMS的好处是用尽量少的新生代,经验值是128M-256M, 然后老生代利用CMS并行收集, 这样能保证系统低延迟的吞吐效率。 实际上cms的收集停顿时间非常的短,2G的内存, 大约20-80ms的应用程序停顿时间
  6. 系统停顿的时候可能是GC的问题也可能是程序的问题,多用jmap和jstack查看,或者killall -3 java,然后查看java控制台日志,能看出很多问题。(相关工具的使用方法将在后面的blog中介绍)
  7. 仔细了解自己的应用,如果用了缓存,那么年老代应该大一些,缓存的HashMap不应该无限制长,建议采用LRU算法的Map做缓存,LRUMap的最大长度也要根据实际情况设定。
  8. 采用并发回收时,年轻代小一点,年老代要大,因为年老大用的是并发回收,即使时间长点也不会影响其他程序继续运行,网站不会停顿
  9. JVM参数的设置(特别是 –Xmx –Xms –Xmn -XX:SurvivorRatio  -XX:MaxTenuringThreshold等参数的设置没有一个固定的公式,需要根据PV old区实际数据 YGC次数等多方面来衡量。为了避免promotion faild可能会导致xmn设置偏小,也意味着YGC的次数会增多,处理并发访问的能力下降等问题。每个参数的调整都需要经过详细的性能测试,才能找到特定应用的最佳配置。
promotion failed: 垃圾回收时promotion failed是个很头痛的问题,一般可能是两种原因产生,第一个原因是救助空间不够,救助空间里的对象还不应该被移动到年老代,但年轻代又有很多对象需要放入救助空间;第二个原因是年老代没有足够的空间接纳来自年轻代的对象;这两种情况都会转向Full GC,网站停顿时间较长。 解决方方案一: 第一个原因我的最终解决办法是去掉救助空间,设置-XX:SurvivorRatio=65536 -XX:MaxTenuringThreshold=0即可,第二个原因我的解决办法是设置CMSInitiatingOccupancyFraction为某个值(假设70),这样年老代空间到70%时就开始执行CMS,年老代有足够的空间接纳来自年轻代的对象。 解决方案一的改进方案: 又有改进了,上面方法不太好,因为没有用到救助空间,所以年老代容易满,CMS执行会比较频繁。我改善了一下,还是用救助空间,但是把救助空间加大,这样也不会有promotion failed。具体操作上,32位Linux和64位Linux好像不一样,64位系统似乎只要配置MaxTenuringThreshold参数,CMS还是有暂停。为了解决暂停问题和promotion failed问题,最后我设置-XX:SurvivorRatio=1 ,并把MaxTenuringThreshold去掉,这样即没有暂停又不会有promotoin failed,而且更重要的是,年老代和永久代上升非常慢(因为好多对象到不了年老代就被回收了),所以CMS执行频率非常低,好几个小时才执行一次,这样,服务器都不用重启了。 -Xmx4000M -Xms4000M -Xmn600M -XX:PermSize=500M -XX:MaxPermSize=500M -Xss256K -XX:+DisableExplicitGC -XX:SurvivorRatio=1 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:+CMSClassUnloadingEnabled -XX:LargePageSizeInBytes=128M -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=80 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+PrintClassHistogram -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -Xloggc:log/gc.log CMSInitiatingOccupancyFraction值与Xmn的关系公式 上面介绍了promontion faild产生的原因是EDEN空间不足的情况下将EDEN与From survivor中的存活对象存入To survivor区时,To survivor区的空间不足,再次晋升到old gen区,而old gen区内存也不够的情况下产生了promontion faild从而导致full gc.那可以推断出:eden+from survivor < old gen区剩余内存时,不会出现promontion faild的情况,即: (Xmx-Xmn)*(1-CMSInitiatingOccupancyFraction/100)>=(Xmn-Xmn/(SurvivorRatior+2))  进而推断出:

 参考图:  

四,JVM 内存参数分析实例

环境:OS:Linux version 2.6.9-79.custome.ELxenU cpu: 4 * Intel(R) Xeon(R) CPU E5410 @ 2.33GHz (双核) memory:4G


1

de style="line-height: 16px; background-color: inherit; font-family: Consolas, ‘Bitstream Vera Sans Mono‘, ‘Courier New‘, Courier, monospace !important; font-size: 1em !important;" >-server -Xmx2g -Xms2g -Xmn256m -XX:PermSize=192m -Xss256k -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70de>

-Xmx2g 最大堆内存2G
-Xms2g 最小内存2G
-Xmn256m 新生代内存256m 整个堆大小=年轻代大小 + 年老代大小 + 持久代大小。持久代一般是固定大小的(例如64m、96m),所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。
-XX:PermSize=192m 持久代 192m
-Xss256k 指定线程桟大小256K
-XX:LargePageSizeInBytes=128m 指定Java heap的分页页面大小为128M
-server 可以使得新生代采用并行GC,年老代采用串行
-XX:+DisableExplicitGC
-XX:+UseConcMarkSweepGC 指定在Old Generation使用concurrent gc ,启用CMS低停顿垃圾收集器。GC线程和应用线程并行
-XX:+CMSParallelRemarkEnabled
-XX:+UseCMSCompactAtFullCollection
-XX:+UseFastAccessorMethods
-XX:+UseCMSInitiatingOccupancyOnly
-XX:CMSInitiatingOccupancyFraction=70

五. 内存回收

GC:垃圾回收。回收的是堆和方法区的内存。

基本原理:找到不被使用的对象,然后回收内存。使用收集器的方式实现GC。

A)怎么找到?从根集合出发,找出无引用的对象。

根集合对象: 当前运行线程栈上引用的对象,常量及静态变量,传到本地方法且没有被本地方法释放的对象引用。

B)收集器

按回收算法为两种: 引用计数收集器,跟踪收集器。

引用计数采用算法:原理是此对象有一个引用,即增加一个计数,删除一个引用则减少一个计数。垃圾回收时,只用收集计数为0的对象。

跟踪收集器采用算法:复制,标记-清除,标记-压缩。

按分区对待的方式分: 增量收集器(jdk5开始废弃),分代收集器。

增量收集器:就是通过一定的回收算法,把一个长时间的中断,划分为很多个小的中断,通过这种方式减少GC对用户程序的影响。

分代收集:对象存活的时间有长短,基于此将堆分为多个代,不同的代采用不同的GC方式。

按吞吐量和响应时间(暂停时间)分为: 串行收集器,并行收集器,并发收集器。

C)评估垃圾回收策略的两个重要度量

吞吐量:JVM花费在垃圾回收上的时间越长,则吞吐量越低
暂停时间:JVM垃圾回收过程当中有一个暂停期,在暂停期间,应用程序不能运行
串行收集器:单线程(单CPU)进行垃圾回收的工作。
–适用情况:数据量比较小;单处理器下并且对响应时间无要求的应用。
–缺点:只能用于小型应用
并行收集器:多个线程同时进行垃圾回收的工作。
–适用情况:”对吞吐量有高要求”,多CPU、对应用响应时间无要求的中、大型应用。举例:科学计算。
–缺点:应用响应时间可能较长
并发收集器:传说中的CMS。垃圾回收器的一些工作与应用程序同时进行。
–适用情况:”对响应时间有高要求”,多CPU、对应用响应时间有较高要求的中、大型应用。举例:Web服务器/应用服务器。

D)GC类型

GC有两种类型:Minor GC(Scavenge GC)和Full GC。

Minor GC:对新生代内存进行GC。

Full GC:对新生代,旧生代,持久代都进行GC。

Full GC可能的原因:

a)老年代或持久代空间满。

b)老年代采用CMS GC,GC日志出现prmotion failed和concurrent mode failure时可能触发。

prmotion failed:Minor GC是,S0(S1)放不下,放入旧生代时,仍然放不下造成的。

concurrent mode failure:CMS GC的过程中,有对象放入旧生代,此时旧生代空间不够。

c)统计得到Minor GC后存活对象放入旧生代的平均大小大于旧生代剩余空间。

d)System.gc(),只是”建议”JVM回收内存,不是强制。

六. 为何内存溢出:

既然都有GC,为什么还有内存被用尽(当然除了突然申请大空间)。这里更想说的是新生代和老年代被耗尽。

这是因为jvm有四种引用类型,不同的引用,GC的条件是不一样的。

A)四种引用

软引用:SoftReference,弱引用:WeakReference ,虚引用:PhantomReference。

软引用:内存不足,或软引用不经常使用时会被回收。适用于做缓存。

弱引用:使用弱引用创建的对象本身没有强引用,GC时一定会被回收。

虚引用:虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。

除此之外都是强引用,我们一般创建一个对象时的引用就是强引用。对象被强引用,是不会不垃圾回收的。

B)内存溢出(泄露)

两种理解,

一是需要使用的对象在不断增加,直到需要分配的jvm内存超出了无法满足,于是产生溢出。

二是无用的对象在不断增加,但又无法回收,于是产生泄露。

泄露的对象有两个特点,首先,这些对象是可达的,即在有向图中,存在通路可以与其相连;其次,这些对象是无用的,即程序以后不会再使用这些对象。这些对象不会被GC所回收,然而它却占用内存


CMSInitiatingOccupancyFraction <=((Xmx-Xmn)-(Xmn-Xmn/(SurvivorRatior+2)))/(Xmx-Xmn)*100

例如:

当xmx=128 xmn=36 SurvivorRatior=1时 CMSInitiatingOccupancyFraction<=((128.0-36)-(36-36/(1+2)))/(128-36)*100 =73.913

当xmx=128 xmn=24 SurvivorRatior=1时 CMSInitiatingOccupancyFraction<=((128.0-24)-(24-24/(1+2)))/(128-24)*100=84.615…

当xmx=3000 xmn=600 SurvivorRatior=1时  CMSInitiatingOccupancyFraction<=((3000.0-600)-(600-600/(1+2)))/(3000-600)*100=83.33

CMSInitiatingOccupancyFraction低于70% 需要调整xmn或SurvivorRatior值。
(8000-3000)-(3000-3000/3)/(8000-3000)*100=60

(4000-1500)-(1500-1500/3)/(4000-1500)*100=
60

我自己的一个配置:
$JAVA_ARGS
.=
"
-Dresin.home=$SERVER_ROOT
-server
-Xmx8000M
-Xms8000M
-Xmn3000M
-XX:PermSize=500M
-XX:MaxPermSize=500M
-Xss1024K
-XX:+DisableExplicitGC
-XX:SurvivorRatio=1
-XX:+UseConcMarkSweepGC
-XX:+UseParNewGC
-XX:+CMSParallelRemarkEnabled
-XX:+UseCMSCompactAtFullCollection
-XX:CMSFullGCsBeforeCompaction=0
-XX:+CMSClassUnloadingEnabled
-XX:LargePageSizeInBytes=128M
-XX:+UseFastAccessorMethods
-XX:+UseCMSInitiatingOccupancyOnly
-XX:CMSInitiatingOccupancyFraction=55
-XX:SoftRefLRUPolicyMSPerMB=0
-XX:+PrintClassHistogram
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+PrintHeapAtGC
-Xloggc:log/gc.log
";

使用这个配置以后,在GC日志中没有发现任何Full GC,所以网站不会有较大的停顿,但是使用jstat -gc 发现full gc 次数还是有的,原因是CMS GC,也就是对老年代的GC,也有显示在这里的FULL GC统计次数之内,不过CMS GC是并发低停顿的,所以对网站影响非常小,特别强调,CMS不是完全没有停顿,是停顿的时间很少,原因是:

这张图表示的是CMS在执行Full GC的过程,这个过程包括了6个步骤:
# STW initial mark
# Concurrent marking
# Concurrent precleaning
# STW remark
# Concurrent sweeping
# Concurrent reset

在这六个步骤中,有两个步骤需要STW,分别是:initial mark和remark(如图所示)。而其它的四个步骤是可以和application“并发”执行,所以也就2个步骤会暂停应用服务,所以就减少了服务暂停的时间

时间: 2024-10-09 20:35:57

jvm运行时分析的相关文章

JVM运行时数据区域分析

Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同数据区域.这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则是依赖用户线程的启动和结束而建立和销毁. 原文链接:http://sparkyuan.me/2016/04/22/JVM运行时数据区域/ ,转载请注明出去 程序计数器(PC) 程序计数器(Program Counter Register)是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码行号指示器. - 当前线

[转]JVM运行时内存结构

目录[-] 1.为什么会有年轻代 2.年轻代中的GC 3.一个对象的这一辈子 4.有关年轻代的JVM参数 1.为什么会有年轻代 我们先来屡屡,为什么需要把堆分代?不分代不能完成他所做的事情么?其实不分代完全可以,分代的唯一理由就是优化GC性能.你先想想,如果没有分代,那我们所有的对象都在一块,GC的时候我们要找到哪些对象没用,这样就会对堆的所有区域进行扫描.而我们的很多对象都是朝生夕死的,如果分代的话,我们把新创建的对象放到某一地方,当GC的时候先把这块存“朝生夕死”对象的区域进行回收,这样就会

Java 进阶(一) JVM运行时内存模型

1.JVM运行时数据区域的划分 a.程序计数器(Program Counter Register) 一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器.每个线程拥有独立的一个计数器,如果当前执行的是Native方法,则计数器值为空. b.JVM栈(Java Virtual Machine Stack) 描述Java方法执行的内存模型,每个方法在执行的同时都会创建一个栈帧(Stacks Frame)用于存储局部变量表,操作数栈,动态链接,方法出口等信息. 每一个方法从调用直至执行完成

jvm运行时内存划分

(根据<深入理解java虚拟机>这本书总结) 本文主要解释jvm内存模型,以及各个部分的作用.都是自己总结的给自己看的通俗语言,未用专业术语的见谅. 一.为什么要了解jvm内存模型? 在了解一个类的编译-加载-内存分配-初始化所有过程前,要先了解jvm的内存模型.这样对整个java体系可能会更加便于理解.当然,如果不理解这些,也是没关系的,照样可以进行java开发. 二.jvm内存模型 1.根据自己的理解举个最简单的例子,一个main方法启动,进程运行,在这个过程中,会调用方法.开启多个线程.

jvm运行时内存解析

一.jvm的概念 在了解jvm的概念之前,我们先来了解java平台的逻辑结构,图片来自<深入java虚拟机> 从图中我们可以看到jdk包含了jre,java语言和java开发工具和Api,jre包含了java运行的基础类库和java虚拟机,java虚拟机支撑着java程序的运行. jvm(java virtual machine)翻译为java虚拟机,从字面上来理解,jvm就是一个虚拟的机器,其实类似于一个操作系统,通过软件去虚拟出一个虚拟机,帮助我们管理计算机的内存和调用计算机的硬件等等.而

JVM运行时数据区与JVM堆内存模型小结

前提 JVM运行时数据区和JVM内存模型是两回事,JVM内存模型指的是JVM堆内存模型. 那JVM运行时数据区又是什么? 它包括:程序计数器.虚拟机栈.本地方法栈.方法区.堆. 来看看它们都是干嘛的 程序计数器:保存当前线程执行的指令的地址(大意如此). 虚拟机栈:由栈帧组成,而每个栈帧又包括局部变量表.操作数栈.动态连接(调用其他方法).出口(被调用时返回值) -- 每个栈帧就代表了一个方法的执行. 本地方法栈:类似虚拟机栈,只不过方法改成了native方法. 方法区:保存了类的各种信息.类的

JVM运行时数据区

本篇主要介绍一下,JVM运行时数据区的内容. 首先大概介绍一下下图所示的内容.JVM运行时数据区主要分为了两大部分的内容:线程共有的方法区(Method Area)和堆(Heap).线程私有的虚拟机栈(VM Stack),本地方法栈(Native Method Stack)和程序计数器(Program Counter Register).在数据区下面的执行引擎中又包含了:即时编译器(JITCompiler)和垃圾收集器(GC).GC主要用于回收线程共享的区域(方法区和堆),对于私有的内存区域则方

JVM【第二回】:【JVM运行时数据区域详解】

上一回对JVM运行时数据区域的组织结构进行了概述,这一回将对各个组成进行详解. 程序计数器[Program Counter Register] 程序计数器是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的行号指示器.在虚拟机的概念模型里,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支.循环.跳转.异常处理.线程恢复等基础功能都需要依赖这个计数器完成. 由于Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,在任何一个确定的

jvm特性与原理----------&gt;jvm运行时数据区分区

1.概述: 内存分区:JVM会把自己所管理的所有内存区域进行分区. 各个区域的服务对象 各个区域中分别存放了什么内容 存放的数据是如何创建的 这些数据在各个区域中存放,存储的布局是什么样的 如何访问存放在不同内存区域的数据 各个区域的创建和销毁时间 随着进程的启动和结束而创建和销毁 随着线程的启动和结束而创建和销毁 各个区域服务过程中可能产生的问题(异常) 各个区域中可能产生的异常 如何解决上述各种异常 2.JVM内存分区 3.JVM内存各个区域的比较   JVM内存分区(JVM运行时数据区)