JVM启动参数:java -server -Xms1G -Xmx1G -Xmn256m -XX:PermSize=64m -XX:MaxPermSize=128m -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+HeapDumpOnOutOfMemoryError
-Xloggc:island_gc_3_201304161720.log -jar /data/game.jar 3
VM_235_195:~ # jmap -heap 8180 Attaching to process ID 8180, please wait... Debugger attached successfully. Server compiler detected. JVM version is 20.8-b03 using parallel threads in the new generation. using thread-local object allocation. Concurrent Mark-Sweep GC Heap Configuration: MinHeapFreeRatio = 40 MaxHeapFreeRatio = 70 MaxHeapSize = 1073741824 (1024.0MB) NewSize = 268435456 (256.0MB) MaxNewSize = 268435456 (256.0MB) OldSize = 5439488 (5.1875MB) NewRatio = 2 SurvivorRatio = 8 PermSize = 67108864 (64.0MB) MaxPermSize = 134217728 (128.0MB) Heap Usage: New Generation (Eden + 1 Survivor Space): capacity = 241631232 (230.4375MB) used = 191160600 (182.3049545288086MB) free = 50470632 (48.132545471191406MB) 79.11253790238507% used Eden Space: capacity = 214827008 (204.875MB) used = 166785816 (159.0593490600586MB) free = 48041192 (45.815650939941406MB) 77.6372661672037% used From Space: capacity = 26804224 (25.5625MB) used = 24374784 (23.24560546875MB) free = 2429440 (2.31689453125MB) 90.93635391198045% used To Space: capacity = 26804224 (25.5625MB) used = 0 (0.0MB) free = 26804224 (25.5625MB) 0.0% used concurrent mark-sweep generation: capacity = 805306368 (768.0MB) used = 34816824 (33.20391082763672MB) free = 770489544 (734.7960891723633MB) 4.323425889015198% used Perm Generation: capacity = 75055104 (71.578125MB) used = 44924728 (42.84355926513672MB) free = 30130376 (28.73456573486328MB) 59.85566018268391% used |
VM_235_195:~ # jmap -histo:live 8180
num #instances #bytes class name
----------------------------------------------
Total 1107232 78045936
2013-04-18 18:42:00,476 WARN :(Memory Monitor) com.ztgame.common.MemoryManager - 服务器占用内存183M
VM_235_195:~ # jstat -gcutil -h5 8180 5s S0 S1 E O P YGC YGCT FGC FGCT GCT 0.00 95.35 90.25 10.24 59.89 371 4.785 5 1.378 6.163 0.00 95.35 95.12 10.24 59.89 371 4.785 5 1.378 6.163 0.00 95.35 99.14 10.24 59.89 371 4.785 5 1.378 6.163 60.76 0.00 3.74 10.45 59.89 372 4.799 5 1.378 6.177 60.76 0.00 6.08 10.45 59.89 372 4.799 5 1.378 6.177 60.76 0.00 9.81 10.45 59.89 372 4.799 5 1.378 6.177 |
-XX:NewRatio 是指
Old Generation/Young Generation 的比值,比如上图中显示为2就代表 2:1,但是如果设置了Xmn的情况下,该参数起不了作用!
-XX:SurvivorRatio 是指Eden/survivor的比值,比如上图中显示为8就代表8:1
上图中触发了一次 Young GC
young GC后,Eden中活对象copy到to survivor(S0)中,大对象直接进老生代Old。
From survivor(S1)中相对老的活对象进入老生代,相对年轻的对象进入to survivor(S0)中。
如果to survivor(S0)放不下活对象,则这些活对象直接进入old。
经历过young GC,Eden和from survivor都变成空的内存区域,to survivor(S0)存储有活的对象。
To survivor和from survivor角色互换,也就是这次GC后,S0 变成From survivor,S1变成了to survivor
新生代(Young Generation)
大部分的对象的内存分配和回收在这里完成。
Eden
新建的对象分配在此,新生代GC后被清空。
Survivor
存储至少经过一次GC存活下来的对象,以增大该对象在提升至老生代前被回收的机会。
From Space
在新生代GC后被清空,GC后存活的对象放入To space或老生代。
To Space
Eden中在新生代GC后存活的对象部分放在此。From Space中在新生代GC后存活的对象部分放在此。
老生代(Old Generation)
永生代(Permanent Generation)
java堆由Perm区和Heap区组成,Heap区则由Old区和New区组成,而New区又分为Eden区,From区,To区,Heap={Old+NEW={Eden,From,To}},old 现在就是concurrent mark-sweep generation。
JVM采用一种分代回收(generational collection)的策略,用较高的频率对年轻的对象(young generation)进行扫描和回收,这种叫做minor collection,而对老对象(old generation)的检查回收频率要低很多,称为major collection。这样就不需要每次GC都将内存中所有对象都检查一遍。
GC不会在主程序运行期对PermGen Space进行清理,所以如果你的应用中有很多CLASS的话,就很可能出现PermGen Space错误。
根据如上观察数据: New Generation (Eden + 1 Survivor Space),也就是
New Generation used=Eden Space used +To Space used
Xmn的256m= New Generation capacity + To Space capacity =Eden Space capacity+ From Space capacity+ To Space capacity (From Space capacity和To Space capacity 分别占Xmn的1/10)
Xmx 1G= New Generation capacity + To Space capacity+concurrent mark-sweep generation capacity
Runtime.getRuntime().totalMemory()-Runtime.getRuntime(). freememory()= New Generation used+concurrent mark-sweep generation used
看来JAVA本身语言输出的是不包含持久代的
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 8180 root 15 0 1412m 607m 10m S 0 8.7 1:40.44 java |
那么,为什么top 出来的RES值不等于堆内存(sum(eden+servivor+old))+ Perm 内存的大小呢?
The total virtual memory used is the sum of the maximum heap + thread stacks + direct memory + perm gen + share libraries. This never shrinks.
意思是说,真实的JAVA应用内存占用=最大堆内存+线程的栈占用+直接内存+持久代+共享库
JVM 中还有栈内存,JNI等,每个线程还得占据一定的内存
JVM除了堆内存外,还有栈内存和直接内存,栈空间每个线程是固定的,而占用大小基本固定而且可以忽略,而直接内存并不是虚拟机运行时数据区的一部分,不受JVM的GC管理,以native的方式分配内存。具体请参考 http://blog.csdn.net/jiangguilong2000/article/details/8821420