JVM
JVM内存管理--运行时数据区
JVM大体由五个部分组成,分别为JVM Stack、Native Stack、Program Counter Register、Java Heap、Method Area。其中JVM Stack、Native Stack、Program Counter Register为每个线程私有,然而Java Heap、Method Area为所有线程共享。每个对象都是由它对应的内部数据和外置的、可以由类提供共享给各个对象的各个方法组成。方法是外部代码,由每个实例化出来的对象可以调用的,而 Java Heap主要是用来存放这些对象的,对于JVM来说,Java Heap所占据的空间最大。
两类JVM管理的内存
JVM管理的内存段可以分为两大类:线程共享内存和线程私有内存。
线程共享内存
- Method Area : 存储jvm加载的class、常量、静态变量、即时编译器编译后的代码等。
- Java Heap :存储java的所有对象实例、数组等。
线程私有内存
- Program Counter Register : 每个线程都有自己的计数寄存器,存储当前线程执行字节码的地址。
- JVM Stack : jvm会为每个运行线程分配一个栈区,线程调用方法时和方法返回时会进行入栈和出栈操作。
- Native Stack : 与 jvm stack 类似,只不过此区域是为调用本地方法服务。
Java Heap Size Options
http://docs.oracle.com/cd/E13222_01/wls/docs81/perform/JVMTuning.html
Task | Option | Recommended Value |
---|---|---|
Setting the New generation heap size | -XX:NewSize | Set this value to a multiple of 1024 that is greater than 1MB. As a general rule, set Be sure to increase the New generation as you increase the number of processors. Memory allocation can be parallel, but garbage collection is not parallel. |
Setting the maximum New generation heap size | -XX:MaxNewSize | Set this value to a multiple of 1024 that is greater than 1MB |
Setting New heap size ratios | -XX:SurvivorRatio | The New generation area is divided into three sub-areas: Eden, and two survivor spaces that are equal in size. Configure the ratio of the Eden/survivor space size. Try setting this value to 8, and then monitor your garbage collection. |
Setting minimum heap size | -Xms | Set the minimum size of the memory allocation pool. Set this value to a multiple of 1024 that is greater than 1MB. As a general rule, set minimum heap size (-Xms) equal to the maximum heap size (-Xmx) to minimize garbage collections. |
Setting maximum heap size | -Xmx | Set the maximum size of the memory allocation pool. Set this value to a multiple of 1024 that is greater than 1MB. |
参数 | 说明 |
---|---|
-Xmx | young generation 和 old generation总共可用的最大空间 |
-Xms | young generation 和 old genertaion二者初始空间。没分配的叫做reserved,再没有的话,向内核申请,如果内核没有内存的话,想办法使用LRU算法从其他程序里腾出内存给它。 |
-XX:NewSize | young generation初始空间 |
-XX:MaxNewSize | young generation最大空间 |
-XX:PermSize | permanent generation初始空间 |
-XX:MaxPermSize | permanent generation最大空间 |
参数 -Xmx 和 -Xms 经常使用,使用的方式是,在jvm启动时将该参数及其对应的值传递给jvm,具体合适传递哪?一般来讲,启动tomcat的话,在catalina.sh中有两个环境变量:CATALINA_OPTS、JAVA_OPTS。CATALINA_OPTS仅对启动运行tomcat实例的jvm虚拟机有效。JAVA_OPTS对本机上的所有JVM有效。如果机器上不仅仅有tomcat实例,建议使用CATALINA_OPTS。可以直接编辑catalina.sh,也可以使用命令设定,例如:
$ export CALALINA_OPTS="-Xmx256m"
The memory structure of a JVM process
对于Java Heap而言,分为 young generation、old generation、permanent generation三个区域。young generation又可分为 to、from、eden三个子区域,之所以分成这三个子区域主要原因是在young generation上面的垃圾收集算法或者叫垃圾收集器,会分别实现young generation、old generation、permanent generation三个区域移动对象之后,完成gc。创建的对象在young generation中过了一定存活时间以后,依然被采用的,那么该对象就会从young generation挪到old generation。如果有些对象创建以后不会被删除的,那么该对象就会被存放在permanent generation。
JVM Memory Handling
- When the JVM starts, the host OS assigns a dedicated( 专注的,投入的; 献身的; 专用的;) memory space to that VM【vm会从操作系统那里取到一定内存空间】
- The VM allocates memory to the application within that dedicated memory space【vm会按照特定的格式划分区段,之所以划分是为了让垃圾回收器完成垃圾回收】
- The VM frees memory automatically via(经过; 通过,凭借; 取道;) garbage collectors
- Garbage Collection is an expensive(昂贵的,花钱多的; 豪华的;) algorithm
Garbage Collectors
如果不考虑permanent generation的话,内存区域大体可以分为以下三个部分:
- Eden Space: where objects ara born
- Survivor Spaces : Where objects mature(成熟),contains to, from。
- Tenured Space : Where objects grow old and die
其中 Eden Space 和 Survivor组成的是young generation。Tenured Space表示old generation。
JVM Memory Layout
New/Young - Recently created object
Old - Long lived object
Perm - JVM classes and methods
Garbage Collector
- Collecting unsed java object
- Cleaning memory
- Minor GC : Collection memory in New/Young generation
- Major GC( Full GC ) : Collection memory in old generation
young generation和old generation的gc的频率不同,算法也不同。不断地执行垃圾回收,腾出空间,主要是针对young generation实现的,对young generation实现垃圾回收的叫做Minor GC,对old generation实现垃圾回收的叫做Major GC。java当中垃圾回收器本身有多种实现方案,即便是Minor GC、Major GC。
Minor GC
注意垃圾回收不是实时进行的,而是积攒到一定的量才会进行操作。执行垃圾回收的过程中其他的线程无法工作,因为其非常消耗资源,会占据整个cpu,这种垃圾回收算法也称之为stop the world,这也就是我们日常生活中使用andriod手机假死的原因。与此不同的苹果ios,是用object-c开发的,程序直接运行在硬件之上,其一:性能好,不用虚拟机解释、运行代码;其二:object-c自己可以实现内存管理,内存回收是及时的,不存在垃圾回收的过程。
Major GC
- Old Generation
- Mark and compact
- Slow ( 1st - goes through the entire heap, marking unreachable objects. 2nd - unreachable objects are compacted )。
对于old generation的垃圾回收一般用Mark and compact( 标记清除算法)实现的,这种垃圾回收的工作恒比较慢,分为两个阶段,第一个步要遍历整个堆内存,标记不再使用的对象,第二步将不再使用的对象一起打包一次性回收。Major GC发生的过程才是真正的stop the world发生的过程,一般发声Major GC原因是old generation 中的对象过多,而大多数的java程序发生Major GC 很少,因为对象被送到old generation区域的少之又少,在到达old generation之前已经被回收了。一旦发声full gc,就需要等待该过程完成,可能也需要手动释放一些堆空间。
根据业务运行模型和内存使用方式来指定不同区域的大小。
性能监控工具
常见问题:OutOfMemoryError:内存不足。引发该问题的原因有内存泄漏(代码问题)、线程死锁、锁竞争(Lock Contention)、Java消耗过多的CPU等等。
jps
jps( java machine process status tool )
监控jvm进程状态信息。jps本身也是使用java开发的,所以它本身也运行这一个java进程。
jps [options] [hostid]
-m :输出传入main方法的参数
-l :显示main类或者jar文件的完全限定名称(也就是完整类名)
-v :显示jvm指定的参数(也就是启动jvm的时候传递了哪些参数给它)
[root@app1 ~]# jps
3808 Jps
784 Bootstrap
[root@app1 ~]# jps -m -l # 查看真正启动jvm的程序或者类是什么
3730 sun.tools.jps.Jps -m -l
784 org.apache.catalina.startup.Bootstrap start
[root@app1 ~]#
[root@app1 ~]# jps -m -l -v
784 org.apache.catalina.startup.Bootstrap start -Djava.util.logging.config.file=/usr/soft/apache-tomcat-7.0.76/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Xms2048m -Xmx32768m -Xss4096K -XX:PermSize=1024m -XX:MaxPermSize=2048m -Djdk.tls.ephemeralDHKeySize=2048 -Djava.endorsed.dirs=/usr/soft/apache-tomcat-7.0.76/endorsed -Dcatalina.base=/usr/soft/apache-tomcat-7.0.76 -Dcatalina.home=/usr/soft/apache-tomcat-7.0.76 -Djava.io.tmpdir=/usr/soft/apache-tomcat-7.0.76/temp
4056 sun.tools.jps.Jps -m -l -v -Denv.class.path=.:/usr/jdk64/jdk1.7.0_67/lib/dt.jar:/usr/jdk64/jdk1.7.0_67/lib/tools.jar -Dapplication.home=/usr/jdk64/jdk1.7.0_67 -Xms8m
[root@app1 ~]#
jstack
用于查看某个java进程内的线程堆栈信息。
jstack [options] pid
-l long listings 输出完整的锁信息。可以指定输出某一项。
-m 混合模式,即会输出java堆栈及c/c++堆栈信息
哪一个java进程最耗cpu? top->jstack
jmap
jmap (jvm mamory map) :查看堆内存使用情况。
jmap [options] pid
-heap :详细输出堆内存空间使用状态信息
-histo[:live] :查看堆内存中的对象数目、大小统计结果。
[root@app1 ~]# jmap
Usage:
jmap [option] <pid>
(to connect to running process)
jmap [option] <executable <core>
(to connect to a core file)
jmap [option] [server_id@]<remote server IP or hostname>
(to connect to remote debug server)
where <option> is one of:
<none> to print same info as Solaris pmap
-heap to print java heap summary
-histo[:live] to print histogram of java object heap; if the "live"
suboption is specified, only count live objects
-permstat to print permanent generation statistics
-finalizerinfo to print information on objects awaiting finalization
-dump:<dump-options> to dump java heap in hprof binary format
dump-options:
live dump only live objects; if not specified,
all objects in the heap are dumped.
format=b binary format
file=<file> dump heap to <file>
Example: jmap -dump:live,format=b,file=heap.bin <pid>
-F force. Use with -dump:<dump-options> <pid> or -histo
to force a heap dump or histogram when <pid> does not
respond. The "live" suboption is not supported
in this mode.
-h | -help to print this help message
-J<flag> to pass <flag> directly to the runtime system
[root@app1 ~]# jmap 784
Attaching to process ID 784, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 24.65-b04
0x0000000000400000 7K /usr/jdk64/jdk1.7.0_67/bin/java
0x00000031f8400000 153K /lib64/ld-2.12.so
0x00000031f8800000 22K /lib64/libdl-2.12.so
0x00000031f8c00000 1883K /lib64/libc-2.12.so
0x00000031f9000000 142K /lib64/libpthread-2.12.so
0x00000031f9400000 46K /lib64/librt-2.12.so
0x00000031f9800000 585K /lib64/libm-2.12.so
0x00000031fa800000 91K /lib64/libgcc_s-4.4.7-20120601.so.1
0x00000031fd800000 111K /lib64/libresolv-2.12.so
0x00007f28b41eb000 26K /lib64/libnss_dns-2.12.so
0x00007f28bc172000 477K /usr/jdk64/jdk1.7.0_67/jre/lib/amd64/libt2k.so
0x00007f2934178000 512K /usr/jdk64/jdk1.7.0_67/jre/lib/amd64/libfontmanager.so
0x00007f293c1ea000 36K /usr/jdk64/jdk1.7.0_67/jre/lib/amd64/headless/libmawt.so
0x00007f297c11f000 755K /usr/jdk64/jdk1.7.0_67/jre/lib/amd64/libawt.so
0x00007f29e0bf2000 250K /usr/jdk64/jdk1.7.0_67/jre/lib/amd64/libsunec.so
0x00007f29e123a000 44K /usr/jdk64/jdk1.7.0_67/jre/lib/amd64/libmanagement.so
0x00007f29e1442000 112K /usr/jdk64/jdk1.7.0_67/jre/lib/amd64/libnet.so
0x00007f29e1659000 89K /usr/jdk64/jdk1.7.0_67/jre/lib/amd64/libnio.so
0x00007f331872f000 120K /usr/jdk64/jdk1.7.0_67/jre/lib/amd64/libzip.so
0x00007f331894a000 64K /lib64/libnss_files-2.12.so
0x00007f3318b61000 214K /usr/jdk64/jdk1.7.0_67/jre/lib/amd64/libjava.so
0x00007f3318d8c000 63K /usr/jdk64/jdk1.7.0_67/jre/lib/amd64/libverify.so
0x00007f331939b000 14853K /usr/jdk64/jdk1.7.0_67/jre/lib/amd64/server/libjvm.so
0x00007f331a212000 103K /usr/jdk64/jdk1.7.0_67/lib/amd64/jli/libjli.so
[root@app1 ~]# jmap -heap 784
Attaching to process ID 784, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 24.65-b04
using thread-local object allocation.
Parallel GC with 18 thread(s) # 垃圾收集算法
Heap Configuration:
MinHeapFreeRatio = 0
MaxHeapFreeRatio = 100
MaxHeapSize = 34359738368 (32768.0MB)
NewSize = 1310720 (1.25MB)
MaxNewSize = 17592186044415 MB
OldSize = 5439488 (5.1875MB)
NewRatio = 2
SurvivorRatio = 8
PermSize = 1073741824 (1024.0MB)
MaxPermSize = 2147483648 (2048.0MB)
G1HeapRegionSize = 0 (0.0MB)
Heap Usage:
PS Young Generation
Eden Space:
capacity = 4660920320 (4445.0MB)
used = 3455457416 (3295.380989074707MB)
free = 1205462904 (1149.619010925293MB)
74.13680515353671% used
From Space:
capacity = 6815744 (6.5MB)
used = 6811632 (6.4960784912109375MB)
free = 4112 (0.0039215087890625MB)
99.93966909555289% used
To Space:
capacity = 143130624 (136.5MB)
used = 0 (0.0MB)
free = 143130624 (136.5MB)
0.0% used
PS Old Generation
capacity = 1431830528 (1365.5MB)
used = 275154128 (262.4074249267578MB)
free = 1156676400 (1103.0925750732422MB)
19.216947999030232% used
PS Perm Generation
capacity = 1073741824 (1024.0MB)
used = 91206560 (86.98135375976562MB)
free = 982535264 (937.0186462402344MB)
8.494272828102112% used
42967 interned Strings occupying 5456928 bytes.
[root@app1 ~]# jmap -histo:live 784 # 详细显示java堆空间中的每一个对象
num #instances #bytes class name
----------------------------------------------
1: 238261 31749640 [C
2: 48744 30171672 [B
3: 152303 23372728 <constMethodKlass>
4: 152303 19508224 <methodKlass>
5: 13376 16932432 <constantPoolKlass>
6: 13376 10056128 <instanceKlassKlass>
7: 10801 9292768 <constantPoolCacheKlass>
8: 233736 7479552 java.lang.String
9: 43674 4785504 [Ljava.lang.Object;
10: 6485 3820120 <methodDataKlass>
11: 25037 3605328 java.lang.reflect.Method
12: 14301 3046232 java.lang.Class
13: 47576 3044864 java.util.LinkedHashMap$Entry
14: 13333 2737448 [Ljava.util.HashMap$Entry;
15: 54334 2608032 java.util.concurrent.ConcurrentHashMap$HashEntry
16: 4380 2191472 [I
17: 21963 2021432 [[I
18: 38640 1854720 java.util.HashMap$Entry
19: 17256 1794624 java.net.URL
20: 18236 1309960 [S
21: 14735 1296680 java.util.LinkedHashMap
22: 30648 1225920 java.util.ArrayList
23: 5079 1066472 [Ljava.util.concurrent.ConcurrentHashMap$HashEntry;
24: 14417 1038024 org.apache.xerces.dom.DeferredTextImpl
25: 12418 894096 org.apache.catalina.loader.ResourceEntry
26: 14042 835776 [Ljava.lang.String;
27: 6231 797568 org.apache.jasper.compiler.Node$TemplateText
28: 7247 753688 org.apache.xerces.dom.DeferredElementImpl
29: 7749 681912 org.apache.jasper.compiler.Mark
30: 13745 659760 java.lang.ref.WeakReference
31: 10086 645504 org.apache.xerces.dom.DeferredAttrImpl
32: 11230 628880 java.lang.ref.SoftReference
33: 8399 604728 java.util.HashMap
。。。省略
jhat
jhat (jvm heap analysis tool),更多用于代码中的运行状况。
[root@app1 ~]# jhat
ERROR: No arguments supplied
Usage: jhat [-stack <bool>] [-refs <bool>] [-port <port>] [-baseline <file>] [-debug <int>] [-version] [-h|-help] <file>
-J<flag> Pass <flag> directly to the runtime system. For
example, -J-mx512m to use a maximum heap size of 512MB
-stack false: Turn off tracking object allocation call stack.
-refs false: Turn off tracking of references to objects
-port <port>: Set the port for the HTTP server. Defaults to 7000
-exclude <file>: Specify a file that lists data members that should
be excluded from the reachableFrom query.
-baseline <file>: Specify a baseline object dump. Objects in
both heap dumps with the same ID and same class will
be marked as not being "new".
-debug <int>: Set debug level.
0: No debug output
1: Debug hprof file parsing
2: Debug hprof file parsing, no server
-version Report version number
-h|-help Print this help and exit
<file> The file to read
For a dump file that contains multiple heap dumps,
you may specify which dump in the file
by appending "#<number>" to the file name, i.e. "foo.hprof#3".
All boolean options default to "true"
[root@app1 ~]#
jstat
jstat (jvm统计监测工具)
[root@app1 ~]# jstat
invalid argument count
Usage: jstat -help|-options
jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]] # option为必选项
Definitions:
<option> An option reported by the -options option
<vmid> Virtual Machine Identifier. A vmid takes the following form:
<lvmid>[@<hostname>[:<port>]]
Where <lvmid> is the local vm identifier for the target
Java virtual machine, typically a process id; <hostname> is
the name of the host running the target Java virtual machine;
and <port> is the port number for the rmiregistry on the
target host. See the jvmstat documentation for a more complete
description of the Virtual Machine Identifier.
<lines> Number of samples between header lines.
<interval> Sampling interval. The following forms are allowed:
<n>["ms"|"s"]
Where <n> is an integer and the suffix specifies the units as
milliseconds("ms") or seconds("s"). The default units are "ms".
<count> Number of samples to take before terminating.
-J<flag> Pass <flag> directly to the runtime system.
[root@app1 ~]# jstat -gc 784
S0C S1C S0U S1U EC EU OC OU PC PU YGC YGCT FGC FGCT GCT
129024.0 512.0 0.0 0.0 4153856.0 61658.6 1398272.0 120259.0 1048576.0 88442.2 23 1.005 2 0.641 1.646
[root@app1 ~]#
S0C,S1C,S0U,S1U:C表示容量,U表示已用量。
EC,EU:eden区域的容量和已用量。
OC,OU
PC,PU
YGC,YGT:表示新生代的gc次数和耗时
FGC,FGCT:表示FULL GC的次数和耗时
GCT:GC总耗时