JVM project practice

First, start the allocation of memory

    A common question about GC is, at startup, how do we allocate memory? You can basically use -Xmn,-Xmx,-Xms,-Xss,-XX:NewSize,-XX:MaxNewSize,-XX:MaxPermSize,-XX:PermSize,-XX:SurvivorRatio,-XX:PretenureSizeThreshold,-XX:MaxTenuringThreshold Configures the allocation of memory at startup. However, how much specific configuration? The setting is small, frequent GC (even memory overflow), the setting is large, the memory is wasted. Combined with the previous study of memory areas and other functions, try to consider the following suggestions:

  1. -XX:PermSize is smaller than -XX:MaxPermSize as much as possible, -XX:MaxPermSize>=2*-XX:PermSize,-XX:PermSize>64M, generally for machines with 4G memory, -XX:MaxPermSize will not exceed 256M;
  2. -Xms=-Xmx (online server mode) to prevent jitter, the size is limited by the operating system and memory size, if it is a 32-bit system, the general -Xms is set to 1g-2g (assuming 4g memory); in 64-bit On the system, there is no limit, but it is generally about half of the maximum memory of the machine;
  3. -Xmn, in the development environment, you can use -XX:NewSize and -XX:MaxNewSize to set the size of the new generation (-XX:NewSize<=-XX:MaxNewSize), in the production environment, it is recommended to only set -Xmn, generally- The size of Xmn is about 1/2 of -Xms. Do not set it too large or too small. If it is too large, the old age will become smaller, and Full GC will be frequent. If it is too small, Minor GC will be frequent. If you do not set -Xmn, you can use -XX:NewRatio=2 to set it, which is the same effect;
  4. -Xss generally does not need to be changed, the default value is sufficient.
  5. -XX:survivorRatio is generally set to about 8-10, and it is recommended to set it to 10, that is, the size of the Survivor area is 1/10 of the Eden area. Generally speaking, for ordinary Java program applications, after a minorGC, at least 98%-99% Therefore, about 1/10 of the Eden area set in the Survivor area can make the Survivor area accommodate 10-20 Minor GCs before it is full, and then enter the old age, which is the same as the default of -XX:MaxTenuringThreshold The value 15 times also matches. If the XX:SurvivorRatio is set too small, the objects that could have been recovered by the Minor will enter the old age in advance, producing unnecessary full gc; if the XX:SurvivorRatio is set too large, the Eden area will be compressed accordingly.
  6. The default value of -XX:MaxTenuringThreshold is 15, that is to say, after 15 Survivor rotations (that is, 15 minor GCs), it will enter the old generation. If it is set to a small value, the survival time of the young generation objects in the survivor will be reduced, and the time will be shortened in advance. Entering the old generation can improve the efficiency for applications with many old generations. If this value is set to a larger value, the young generation object will be replicated multiple times in the Survivor area, which can increase the survival time of the object in the young generation and increase the probability of being recycled in the young generation. It should be noted that setting -XX:MaxTenuringThreshold does not mean that the object must survive 15 times in the young generation before being promoted to the old generation. It is only a maximum value. In fact, there is a dynamic calculation mechanism. The threshold for entering the old age, whichever is smaller between the threshold and MaxTenuringThreshold.

2. Monitoring tools and methods

    In the process of JVM running, we need to monitor GC in order to ensure stability, high school, or to analyze the cause of GC problems when they occur. The so-called monitoring is actually to analyze the current GC situation. Its purpose is to identify whether the JVM is performing garbage collection efficiently and whether tuning is necessary. By monitoring GC, we can figure out many problems, such as:

  1. Frequency of minor GC and full GC;
  2. The time it takes to perform a GC;
  3. When the objects of the young generation were transferred to the old generation and how much time was spent;
  4. In each GC, other threads are suspended;
  5. What is the effect of each GC, and whether it is not ideal.

    There are two types of tools for monitoring GC: command line tools and graphical tools; the obvious command line tools are:

1. jps: used to query the running JVM process, the commonly used parameters are:

  • -q: only output LVMID, omit the name of the main class;
  • -m: Output the parameters passed to the main class main() function when the virtual machine process starts;
  • -l: output the full class name of the main class, if the process executes a jar package, output the jar path
  • -v: Output JVM parameters when the virtual machine process is started

2. jstat can display data such as class loading, memory, garbage collection, JIT compilation, etc. in the local or remote JVM process in real time. If the startup parameter -verbose:gc is not specified when the service is started, you can use jstat to view the gc situation in real time. jstat has the following options:

  • -class: Monitors the number of class loading, unloading, total space and time consumed by class loading.
  • -gc: Monitor the status of the java heap, including the capacity of the Eden area, the two Survivor areas, the old generation, the permanent generation, etc., to use space, the total GC time and other information.
  • -gccapacity: The monitoring content is basically the same as -gc, but the main output mainly focuses on the maximum and minimum space used by each area of ​​the Java heap.
  • -gcutil: Monitors basically the same as -gc, but the output focuses on the percentage of used space to total space.
  • -gccause: Same as -gcutil, but additionally output the reason for the last gc.
  • -gcnew: Monitor the new generation GC status
  • -gcnewcapacity: The monitoring is basically the same as -gcnew, the output mainly focuses on the maximum and minimum space used.
  • -gcold: Monitor the old generation GC situation.
  • -gcpermcapacity: Output the maximum and minimum space used by the permanent generation.
  • -compiler: Outputs information such as methods compiled by the JIT compiler and time-consuming.
  • -printcompilation: Print methods that have been JIT compiled.

3. jinfo: used to query the properties and parameter values ​​of the currently running JVM. jinfo can use the following options:

  • -flag: Display system defaults for parameters not explicitly specified
  • -sysprops: Print System.getProperties() of the virtual machine process;

4, jmap: used to display the details of the current Java heap and permanent generation.

  • -dump: Generate java heap dump snapshot;
  • -heap:显示java堆详细信息
  • -F:当虚拟机进程对-dump选项没有响应时,可使用这个选项强制生成dump快照。
  • -finalizerinfo:显示F-Queue中等待Finalizer线程执行finalize方法的对象。
  • -histo:显示堆中对象统计信息
  • -permstat:以ClassLoader为统计口径显示永久代内存状态。

5、jhat:用于分析使用jmap生成dump文件,是JDK自带的工具,使用方法为:jhat -J -Xmx512m [file]

不过jhat没有mat好用,推荐使用mat(Eclipse插件:http://www.eclipse.org/mat),mat速度更快,而且是图形界面。

6、jstack:用于生成当前JVM的所有线程快照,线程快照是虚拟机每一条线程正在执行的方法,目的是定位线程出现长时间停顿的原因。

  • -F:当正常输出的请求不被响应时,强制输出线程堆栈。
  • -l:除堆栈外,显示关于锁的附加信息。
  • -m:如果调用到本地方法的话,可以显示c/c++的堆栈。

7、-verbosegc:是一个比较重要的启动参数,记录每次gc的日志。与-verbosegc配合使用的一些常用参数为:

  • -XX:+PrintGCDetails,打印GC信息,这是-verbosegc默认开启的选项;
  • -XX:+PrintGCTimeStamps,打印每次GC的时间戳;
  • -XX:+PrintHeapAtGC:每次GC时,打印堆信息;
  • -XX:+PrintGCDateStamps:打印GC日期,适合于长期运行的服务器;
  • -Xloggc:/home/admin/logs/gc.log制定打印信息的记录日志位置

执行verbosegc打印的gc日志,如下:

  • time:执行GC的时间,需要添加-XX:+PrintGCDateStamps参数才有;
  • collector:minor gc使用的收集器的名字;
  • starting occupancy1: GC执行前新生代空间大小;
  • ending occupancy1: GC执行后新生代空间大小;
  • total occupancy1:新生代总大小
  • pause time1:因为执行minor GC,java应用暂停的时间。
  • starting occupancy3: GC执行前堆区域总大小;
  • ending occupancy3:GC执行后堆区域总大小;
  • total occupancy3:堆区总大小
  • pause time3:Java应用由于执行堆空间GC而停止的时间;

8、可视化工具

    监控和分析GC也有一些可视化工具,比较常见的有JConsole和VisualVM,可以查看http://blog.csdn.net/java2000_wl/article/details/8049707

三、调优方法

    一切都是为了这一步,调优,在调优之前,我们需要记住下面的原则:

  1. 多数的Java应用不需要在服务器上进行GC调优;
  2. 多数导致GC问题的Java应用,都不是因为我们参数设置错误,而是代码问题;
  3. 在应用上线前,优先考虑将机器的JVM参数设置到最优;
  4. 减少创建对象的数量;
  5. 减少使用全局变量和大对象;
  6. GC优化是最后不得已才采用的手段;
  7. 在实际使用中,分析GC情况优化代码比GC参数要多得多;

    GC优化的目的有两个:

  1. 将转移到老年代的对象数量降低到最小;
  2. 减少Full gc的执行时间;

    为了达到上面的目的,一般的,你需要做的事情有:

  • 减少使用全局变量和大对象;
  • 调整新生代的大小到最适合;
  • 设置老年代的大小为最合适;
  • 选择合适的GC收集器;

    真正熟练的使用GC调优,是建立在多次进行GC监控和调优的实战经验上的,进行监控和调优的一般步骤为:

1、监控GC的状态:使用各种JVM工具,查看当前日志,分析当前JVM参数设置,并且分析当前堆内存快照和GC日志,根据实际各区域划分和GC执行时间,觉得是否进行优化;

2、分析结果、判断是否需要优化

    如果各项参数设置合理,系统没有超时日志出现,GC频率不高,GC耗时不高,那么没有必要进行GC优化;如果GC时间超过1-3秒,或者频繁GC,则必须优化;

    注:如果满足下面的指标,则一般不需要进行GC:

  • Minor GC执行时间不到50ms;
  • Minor GC执行不频繁,约10秒一次;
  • full GC执行时间不到1s;
  • Full GC执行频率不算频繁,不低于10分钟1次;

3、调整GC类型和内存分配

    如果内存分配过大或过小,或者采用的GC收集器比较慢,则应该优化调整这些参数,并且先找1台或几台服务器进行beta,然后比较优化过得机器和没有优化的机器的性能对比,并有针对的作出最后的选择;

4、不断的分析和调整

    通过不断的实验和试错,分析并找到最合适的参数。

5、全面应用参数

    如果找到了最适合的参数,则将这些参数应用到所有服务器,并进行后续跟踪。

四、调优实例

 1、机器出现:java.lang.OutOfMemoryError:GC overhead limit exceeded.这个异常代表:GC为了释放很小的空间却消耗了太多的时间,其原因一般有两个:1、堆太小,2、有死循环或大对象;在排查中,首先排除第2个原因,因为这个应用同时在线上运行的,如果有问题,早就挂掉了。所以怀疑是这台机器中堆设置太小;使用ps -ef|grep java查看,发现:


应用的堆区设置只有768m,而机器内存有2g,机器上只跑了这一个Java应用,没有其他需要占用内存的地方。另外,这个应用比较大,需要占用的内存也比较多;基于上面的判断,只需要改变堆中各个区域的大小设置即可,于是修改为下面的情况:


    葛总运行情况发现,相关异常没有在出现;

2、一个服务系统,经常出现停顿,分析原因,发现Full GC时间太长:jstat -gcutil

S0     S1    E     O       P        YGC YGCT FGC FGCT  GCT
12.16 0.00 5.18 63.78 20.32  54   2.047 5     6.946  8.993 

    分析上面的数据,发现Young GC执行了54次,耗时2.047秒,每次Young GC耗时37ms,在正常范围,而Full GC执行了5次,耗时6.946秒,平均每次1.389s,数据显示出来的问题是:Full GC耗时较长,分析该系统的设置发现,NewRatio=9,也就是说:新生代和老年代大小之比为1:9,这就是问题的原因:

  • 新生代太小,导致对象提前进入老年代,触发老年代发生Full GC;
  • 老年代较大,进行Full GC时耗时较大;

     优化的方法是调整NewRatio的值,调整到4,发现Full GC没有再发生,只有Young GC在执行。这就是把对象控制在新生代就清理掉,没有进入老年代。

3、一个应用在性能测试的过程中,发现内存占用率很高,Full GC频繁,使用jmap -dump:fomat=b,file=文件名.hprof pid来dump内存,生成dump文件,并使用Eclipse下的mat差距进行分析,发现:


    从图中可以看出,这个线程存在问题,队列LinkedBlockingQueue引用的大量对象并未释放,导致整个线程占用内存高达378m,此时通知开发人员进行代码优化,将相关对象释放掉即可。

 

 转子:http://www.cnblogs.com/zhguang/p/Java-JVM-GC.html

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326922814&siteId=291194637