Java GC机制及原理 项目实际遇到GC问题解决思路和经验总结

摘要: 1.什么是GC及基础知识介绍 2.垃圾回收策略比较分析 3.trouble shooting GC 命令介绍 4.GC使用工具IBC heap和Jvisualvm 的使用 5.团购系统GC问题经验分享

 

1.什么是GC及基础知识介绍

GC(Garbage Collection) 简称垃圾收集 垃圾回收,JVM内存区域分为:

1.在方法区中(Hotspot 永久代),存储了每个类的信息(包括类的名称、方法信息、字段信息)、静态变量、常量以及编译器编译后的代码等

2.堆(heap)存储对象的信息,分为新生代(Eden,Survivor1,Survivor2)和老年代,永久代

3.程序计数器,存储的数据所占空间的大小不会随程序的执行而发生改变,因此,对于程序计数器是不会发生内存溢出现象(OutOfMemory)的

4.Java栈(stack)是Java方法执行的内存模型

5.本地方法栈则是为执行本地方法(Native Method)服务的

 

 

2. 垃圾回收策略

讲到垃圾回收,那么什么时候对象需要回收,如何去判断对象是存活还是死亡,我们采用引用计数法来判断对象是否存活,当一个对象被引用时,计数器值加1,当引用失效时减1.

强引用与弱引用的区别:

强引用:类似Object obj = new Object();只要强引用还存在,垃圾回收器不会收集被引用的对象

软引用:用来描述还有用但非必需的对象

通过可达性分析算法来判断对象是否需要被回收

垃圾回收策略有 标记清除法(会产生过多的内存碎片),复制法(内存使用率不高),标记整理法

垃圾收集器分类

Serial收集器:发展历史最悠久的收集器

ParNew收集器

Minor GC & Major GC & Full GC

从年轻代空间(包括 Eden 和 Survivor 区域)回收内存被称为 Minor GC

  • Major GC 是清理永久代。
  • Full GC 是清理整个堆空间—包括年轻代和永久代

CMS(Concurrent Mark Sweep)收集器:是一种以获取最短停顿时间为目标的垃圾收集器

 

 

3.GC问题常用命令介绍

jps(Java Virtual Machine Process Status Tool);//虚拟机进程状况工具
jstat;//虚拟机统计信息监视工具
jstat -gc 4588 250 20;//每250毫秒查询进程4588垃圾收集情况 一共查询20次
jstat -gcold 4588;//查看老年代gc存储量
jstat -gcnew 4588;//查看年轻代gc存储量

-gc:监视堆内存情况,包括eden区,s1,s2,老年代和永久代的内存容量
-gcnew:监视新生代GC情况
-gcold:监视老年代GC情况

jinfo;//Java配置信息工具
jmap;//java内存映像工具

使用jmap生成dump文件
jmap -dump:format=b,file=eclipse.bin 14949;//14949进程号
jhat;//虚拟机堆转储快照分析工具
jstack;//java堆栈跟踪工具

 

 

关于GC重要命令介绍

 

关于jps

jps是用于查询jvm进程信息的

主要参数有:

-q 不输出类名、Jar名和传入main方法的参数
-m 输出传入main方法的参数
-l 输出main类或Jar的全限名
-v 输出传入JVM的参数

比如输入

jps -m -l

 

会显示下面的信息

15089 org.apache.catalina.startup.Bootstrap start
27362 org.apache.catalina.startup.Bootstrap start
9043 org.apache.catalina.startup.Bootstrap start
9765 sun.tools.jps.Jps -m -l
8328 org.apache.catalina.startup.Bootstrap start
27179 org.apache.zookeeper.server.quorum.QuorumPeerMain /usr/local/zookeeper-3.4.6/bin/../conf/zoo.cfg
31454 org.apache.catalina.startup.Bootstrap start

 

关于jstack

jstack主要用来查看某个Java进程内的线程堆栈信息

jstack -F 2881

 

主要参数有:

-F  to force a thread dump. Use when jstack <pid> does not respond (process is hung)
-m  不仅会输出Java堆栈信息,还会输出C/C++堆栈信息(比如Native方法)
-l  会打印出额外的锁信息,在发生死锁时可以用jstack -l pid来观察锁持有情况
-h or -help to print this help message

 

关于jmap

jmap用来查看堆内存使用状况,一般结合jhat使用

jmap -heap 7481
jmap -histo:live 1432 | more;//查看堆内存中的对象数目、大小统计直方图,如果带上live则只统计活对象
jmap -permstat 7481;//如果操作系统是64位

打印进程的类加载器和类加载器加载的持久代对象信息,输出:类加载器名称、对象是否存活(不可靠)、对象地址、父类加载器、已加载的类大小等信息

使用jmap -heap pid查看进程堆内存使用情况,包括使用的GC算法、堆配置参数和各代中堆内存使用情况

[root@localhost ~]# jmap -heap 7481
Attaching to process ID 7481, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 24.76-b04

using thread-local object allocation.
Parallel GC with 4 thread(s)

Heap Configuration:
   MinHeapFreeRatio = 0
   MaxHeapFreeRatio = 100
   MaxHeapSize      = 1981808640 (1890.0MB)
   NewSize          = 1310720 (1.25MB)
   MaxNewSize       = 17592186044415 MB
   OldSize          = 5439488 (5.1875MB)
   NewRatio         = 2
   SurvivorRatio    = 8
   PermSize         = 21757952 (20.75MB)
   MaxPermSize      = 85983232 (82.0MB)
   G1HeapRegionSize = 0 (0.0MB)

Heap Usage:
PS Young Generation
Eden Space:
   capacity = 31981568 (30.5MB)
   used     = 11806536 (11.259590148925781MB)
   free     = 20175032 (19.24040985107422MB)
   36.916689012871416% used
From Space:
   capacity = 4718592 (4.5MB)
   used     = 0 (0.0MB)
   free     = 4718592 (4.5MB)
   0.0% used
To Space:
   capacity = 4718592 (4.5MB)
   used     = 0 (0.0MB)
   free     = 4718592 (4.5MB)
   0.0% used
PS Old Generation
   capacity = 82313216 (78.5MB)
   used     = 0 (0.0MB)
   free     = 82313216 (78.5MB)
   0.0% used
PS Perm Generation
   capacity = 22020096 (21.0MB)
   used     = 5066136 (4.831443786621094MB)
   free     = 16953960 (16.168556213378906MB)
   23.00687517438616% used

2942 interned Strings occupying 249928 bytes.

 

一个很常用的情况是:用jmap把进程内存使用情况dump到文件中,再用jhat分析查看。jmap进行dump命令格式如下:

jmap -dump:format=b,file=dumpFileName pid

jmap -dump:format=b,file=/tmp/dump.dat 21711 

jmap -dump:live,format=b,file=xxx 2657

 

用jhat分析dump文件:

jhat -port 9998 /tmp/dump.dat

浏览器端输入http://localhost:9998 可以看到下面的页面:

 

关于jstat

jstat(JVM统计监测工具)

jstat -gc 21711 250 4;//输出的是GC信息,采样时间间隔为250ms,采样数为4

输入内容为:

 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT   
1024.0 1024.0  0.0   544.1  28672.0  23313.6   142336.0   98745.4   57984.0 55759.5 7040.0 6445.8   1213    8.115   3      0.322    8.437
1024.0 1024.0  0.0   544.1  28672.0  23313.6   142336.0   98745.4   57984.0 55759.5 7040.0 6445.8   1213    8.115   3      0.322    8.437
1024.0 1024.0  0.0   544.1  28672.0  23315.6   142336.0   98745.4   57984.0 55759.5 7040.0 6445.8   1213    8.115   3      0.322    8.437
1024.0 1024.0  0.0   544.1  28672.0  23317.7   142336.0   98745.4   57984.0 55759.5 7040.0 6445.8   1213    8.115   3      0.322    8.437

 

要明白上面各列的意义,先看JVM堆内存布局:

可以看出:

堆内存 = 年轻代 + 年老代 + 永久代
年轻代 = Eden区 + 两个Survivor区(From和To)

 

现在来解释各列含义:

S0C、S1C、S0U、S1U:Survivor 0/1区容量(Capacity)和使用量(Used)
EC、EU:Eden区容量和使用量
OC、OU:年老代容量和使用量
PC、PU:永久代容量和使用量
YGC、YGT:年轻代GC次数和GC耗时
FGC、FGCT:Full GC次数和Full GC耗时
GCT:GC总耗时

 

JVM参数含义

-Xms 是指设定程序启动时占用内存大小,一般来讲,大点,程序会启动的 快一点,但是也可能会导致机器暂时间变慢。

-Xmx 是指设定程序运行期间最大可占用的内存大小。如果程序运行需要占 用更多的内存,超出了这个设置值,就会抛出OutOfMemory 异常。

-Xss 是指设定每个线程的堆栈大小。这个就要依据你的程序,看一个线程 大约需要占用多少内存,可能会有多少线程同时运行等。

-Xmn 新生代大小

 

 

4.JVM性能调试工具

常用的JVM调试工具有visualvm(http://visualvm.java.net/),heap analyzer