`

jvm运行时分析

    博客分类:
  • JVM
 
阅读更多

转自:http://blog.163.com/itjin45@126/blog/static/10510751320144201519454/

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

 

参考书籍:

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

 

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

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内存结构:

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 memoryJNI 程序本身也需要分配内存。

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

 

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

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

jvm运行时分析 - 臭脚大仙 - 欢迎光临臭脚大仙的小屋!!

 

显 然,这里的虚拟内存大小变成了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

jvm运行时分析 - 臭脚大仙 - 欢迎光临臭脚大仙的小屋!!

 

列名 描述
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 

jvm运行时分析 - 臭脚大仙 - 欢迎光临臭脚大仙的小屋!!

 

列名 描述
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  

jvm运行时分析 - 臭脚大仙 - 欢迎光临臭脚大仙的小屋!!
列名 描述
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

jvm运行时分析 - 臭脚大仙 - 欢迎光临臭脚大仙的小屋!!

 

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

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

jvm运行时分析 - 臭脚大仙 - 欢迎光临臭脚大仙的小屋!!
 
列名 描述
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
jvm运行时分析 - 臭脚大仙 - 欢迎光临臭脚大仙的小屋!!
 
 
  列名 描述
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  
 
jvm运行时分析 - 臭脚大仙 - 欢迎光临臭脚大仙的小屋!!
 
列名 描述
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 
jvm运行时分析 - 臭脚大仙 - 欢迎光临臭脚大仙的小屋!!
 
 
列名 描述
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
jvm运行时分析 - 臭脚大仙 - 欢迎光临臭脚大仙的小屋!!
 
 
  列名 描述
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   
jvm运行时分析 - 臭脚大仙 - 欢迎光临臭脚大仙的小屋!!
 
列名 描述
Compiled 执行的编译任务次数
Size Number of bytes of bytecode for the method.
Type 编译类型。Compilation type.
Method 类名和方法名。类名使用”/”代替了原命名空间符号”.”

12、类加载情况

jstat -class 20611 500 5
jvm运行时分析 - 臭脚大仙 - 欢迎光临臭脚大仙的小屋!!
 
 
列名 描述
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设置SurvivorEden之间的比值,如果设置为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运行时分析 - 臭脚大仙 - 欢迎光临臭脚大仙的小屋!!

 

 
 
 

四,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不是完全没有停顿,是停顿的时间很少,原因是:

jvm运行时分析 - 臭脚大仙 - 欢迎光临臭脚大仙的小屋!!

 

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

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

分享到:
评论

相关推荐

    JVM运行机制深入分析

    JVM运行机制深入分析,适用于研究java开发的人员,想深入理解jvm

    jvmgc日志分析工具

    适用于jvm运行生成的gc日志文件可视化分析

    JAVA jvm DUMP 内存分析

    性能测试,线程的 dump 看到线程的 死锁,等待 运行状态

    jdk,jvm源码

    jvm源码,jvm-native的源码,jvm支行机制,可对jvm的运行过程进行分析 个人网站:https://www.zhangjunbk.com

    深入JVM内核 - 原理、诊断与优化

    JVM运行机制简介 堆、栈、方法区等 JVM启动流程 内存模型和volatile实例 解释和编译运行的概念 介绍JVM的内部结构、启动流程以及内存模型。并介绍JVM字节码的执行方式。 第三课 常用JVM参数 堆的分配参数 栈分配及...

    jvm的内存结构图的ppt模型分析

    jvm的内存结构图,详细的介绍了jvm运行的模型流程,包括jvm运行的五大内存分布。通过什么是jvm什么是java编程程序的=中的三个兄弟jdk.jvm和jre的区别

    深入JVM内核—原理、诊断与优化

    1、初始化JVM 2、JVM运行机制 3、常用JVM配置参数 4、算法和种类 5、GC参数 6、类 7、性能监控 8、jvm堆分析 9、锁 10、class文件结构 11、字节码执行 12、总结

    深入理解JVM.rar

    每个使用Java的开发者都知道Java字节码是在JRE中运行,而JVM则是JRE中的核心组成部分,承担分析和执行Java字节码的工作,而Java程序员通常并不需要深入了解JVM运行情况就可以开发出大型应用和类库。尽管如此,如果你...

    JVM(Java虚拟机)

    JVM(Java虚拟机)的整个流程:发展,运行区域,垃圾回收器,内存分配策略,垃圾收集,JVM分析工具,JVM优化

    深入理解JVM内存结构及运行原理全套视频加资料.txt

    包括JVM执行过程、虚拟机类加载机制、运行时数据区、GC、类加载器、内存分配与回收策略等,全套视频加资料高清无密码  第1讲 说在前面的话 免费 00:05:07  第2讲 整个部分要讲的内容说明 免费 00:06:58  第3讲...

    JVM详解JVM详解

    详细分析了jvm的运行和内存管理机制

    Java进阶教程解密JVM视频教程

    JVM 是 Java 程序的运行环境,学习 JVM,方能了解 Java 程序是如何被执行的,为进一步深入底层原理乃至程序性能调优打好基础。通过学习这门课程,你将掌握:1. JVM 内存结构的组成、各部分功能作用,学会利用内存...

    《JVM从入门到入魔》笔记.pdf

    1:JVM内存模型:类加载机制【转载、验证、准备、解析、初始化】+类装载器【装载器分类、加载原则】+运行时数据区【方法区、堆、虚拟机栈、本地方法栈、程序计数器】。 2:垃圾回收:垃圾确定【引用计数法、可达性分析...

    论文研究-基于JVM内存模型的String分析 .pdf

    基于JVM内存模型的String分析,王培,程明,本文首先介绍了运行时的Java程序的内存管理模型中的方法区、堆和Java栈等几块内存区域,又介绍了存于堆中的常量池这块比较特殊的内�

    java性能分析 jmap jstack

    java程序性能分析thread dump和heap dump,dump文件:在故障定位(尤其是out of memory)和性能分析的时候,dump文件记录了JVM运行期间的内存占用、线程执行等情况。 heap dump:记录某一时刻JVM堆中对象使用情况,哪些...

    ha456.jar(IBMHeapAnalyzer)JVM内存分析工具

    IBM的heapanalyzer,可以分析dump出的JVM内存快照。在命令行中,进入到jar文件所在目录,输入命令java -Xmx3000m -jar ha456.jar运行。

    java-virtual-machine-analysis.zip_jvm规范

    研究Java平台的核心——虚拟机.为了使Java在不同的平台上顺利运行,研究Java虚拟机(Java virtual ...究,同时结合Sun的《Java虚拟机规范》,总结出实现JVM的一些关键步骤,并提出改进JVM运行效率的建议.

    全面了解JVM组成底层工作原理以及数据结构

    JVM介绍入门到深入,通过全面了解JVM组成底层工作原理以及数据结构,在今后JVM深入分析中全面提升运行性能

Global site tag (gtag.js) - Google Analytics