beginning:
2B brother today to share with you a hard goods, why? Because there are two good things:
First, upgrade the LV2 brother ha ha times cool mood.
Second, to get the company of 2 thousand shares
In the company for two years, and finally become good brothers of the East Columbia.
CMS collector combat:
Combat began, not ready
Construction of Spring Boot Project:
Simulated business scenario Code:
@RestController
public class IndexController {
/***
* 存big对象
* @return
*/
@GetMapping("/put")
public String process() {
ArrayList<User> users = queryUsers();
for (User user:users){
//TODO 业务操作
}
return "ok";
}
private ArrayList<User> queryUsers() {
ArrayList<User> users = new ArrayList<>();
for (int i = 0; i < 50000; i++) {
users.add(new User(i, "java2b"));
}
return users;
}
}
复制代码
public class User {
private int id;
private String name;
private byte[] data;
public User(int id, String name) {
this.id = id;
this.name = name;
data=new byte[1 * 128 * 1024];
}
}
复制代码
Output collector information:
/***
* 打印jvm信息
* @return
*/
@GetMapping("/info")
public String info() {
List<GarbageCollectorMXBean> garbages = ManagementFactory.getGarbageCollectorMXBeans();
StringBuilder stringBuilder = new StringBuilder();
for (GarbageCollectorMXBean garbage : garbages) {
stringBuilder.append("垃圾收集器:名称=" + garbage.getName() + ",收集=" + garbage.getCollectionCount() + ",总花费时间="
+ garbage.getCollectionTime());
// + ",内存区名称=" + Arrays.deepToString(garbage.getMemoryPoolNames()));
stringBuilder.append("\r\n");
}
MemoryMXBean memory = ManagementFactory.getMemoryMXBean();
MemoryUsage headMemory = memory.getHeapMemoryUsage();
long MB = 1024 * 1024;
stringBuilder.append("head堆:");
stringBuilder.append("\t初始(M):" + headMemory.getInit() / MB);
stringBuilder.append("\t最大(上限)(M):" + headMemory.getMax() / MB);
stringBuilder.append("\t当前(已使用)(M):" + headMemory.getUsed() / MB);
stringBuilder.append("\t提交的内存(已申请)(M):" + headMemory.getCommitted() / MB);
stringBuilder.append("\t使用率:" + headMemory.getUsed() * 100 / headMemory.getCommitted() + "%");
return stringBuilder.toString();
}
复制代码
Generating jar package deployed to the server
Startup parameters:
java -Xms256m -Xmx256m -verbose:gc -Xloggc:/root/jvm/gc-cms.log -XX:+UseConcMarkSweepGC -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintHeapAtGC -XX:HeapDumpPath=/root/jvm/dump.hprof -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCTimeStamps -XX:+PrintCommandLineFlags -XX:+PrintFlagsFinal -XX:+PrintGCDetails -XX:+UseCMSCompactAtFullCollection -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.port=6666 -Djava.rmi.server.hostname=192.168.0.31 -jar /root/jvm/jvm-web-0.0.1-SNAPSHOT.jar > catalina.out &
复制代码
JVM parameters of significance here for the next spots.
JVM arguments detailed:
JVM arguments | meaning |
---|---|
-XX:-CMSPrecleaningEnabled | No pre-cleaning, spent the previous article we all know, CMS during this time and concurrent mark and re-mark, there will be a pre-cleanup work, and will try this by waiting 5 seconds to once YGC. In order to avoid time-consuming re-marked in the back of the stage to mark the new generation of the object. |
-XX:+UseConcMarkSweepGC | This parameter will start the CMS collector. The default is the new generation ParNew, Serial can also be set to the new generation of collectors. This parameter is equivalent to -Xconcgc. |
-XX:ParallelGCThreads | Because it is a parallel processor, of course, also possible to specify the number of threads. The default number of concurrent threads are: (ParallelGCThreads + 3) / 4). |
-XX:ConcGCThreads | Or -XX: ParallelCMSThreads; in addition to the above set of threads of the way, you can manually set any of a number of concurrent threads CMS through this two parameters |
-XX:CMSInitiatingOccupancyFraction | Since the CMS collector is not exclusive, the application is still working at the time of garbage collection, we need to set aside enough memory to the application, otherwise it will trigger FGC. CMS GC and when to run it? It can be set via the parameter, which represents the percentage of memory to use the old era. When this threshold is reached it will be executed CMS. The default is 68. If old's memory is growing rapidly, it is recommended to reduce the threshold to avoid FGC, if growth is slow, it can increase the threshold to reduce the number of CMS GC. Improve throughput. |
-XX:+UseCMSCompactAtFullCollection | Since the CMS using labeled cleaning algorithm, memory fragmentation can not be avoided. This parameter specifies once defragmented after CMS. |
-XX:CMSFullGCsBeforeCompaction | Because after each performance will affect defragment, you can use this parameter to set how many times the CMS to conduct a defragmentation, which is memory compression. |
-XX:+CMSClassUnloadingEnabled | It allows recovery of the class metadata. |
-XX:CMSInitiatingPermOccupancyFraction | When the permanent zone occupancy rate of this percentage, CMS started recycling (provided that -XX: + CMSClassUnloadingEnabled activated). |
-XX:UseCMSInitiatingOccupancyOnly | Is performed only represent CMS recovered in time to reach the threshold. |
XX:CMSWaitDuration=2000 | Because CMS GC conditions are relatively simple, the JVM thread has a regular Old scan region, can specify the time interval (in milliseconds) by this parameter, the default is 2s. |
JVM tool parameters:
JVM arguments | meaning |
---|---|
-XX:+PrintGCDateStamps | Print GC logs timestamp |
-XX:+PrintGCDetails | Print GC details |
-XX:+PrintGCTimeStamps | The Indian jvm garbage collection starts running from the time-consuming |
-Xloggc: | The output of garbage collection information to the specified file |
-verbose:gc | Print GC logs |
-XX:+PrintGCApplicationStopedTime | View gc pauses caused by the application |
XX + PrintTenuringDistribution | Objects promotion log |
-XX:+HeapDumpOnOutOfMemoryError | Export dump file when memory overflow |
Start effect:
access:
We find that the new generation with the older alternative of cms is parNew
Request put:
We see the effect through http access method put after:
Results are as follows:
During the operation, we found that a large number of objects into the old era, triggering a full gc, cms been collecting.
Utilization rate reached 99%, cms also did not stop the moment:
Log analysis:
Log Analyzer version 1.0:
We next analyzed to extract a log
[GC (Allocation Failure) 0K->63K(64K), 0.0047147 secs] 10258K->6780K(46144K), [Metaspace: 3434K->3434K(1056768K)], 0.0047613 secs][Times: user=0.02 sys=0.00, real=0.00 secs]
该日志为四个部分:
Full GC:
表明进行了一次垃圾回收,前面没有Full修饰,表明这是一次Minor GC ,注意它不表示只GC新生代,并且现有的不管是新生代还是老年代都会STW。
Allocation Failure:
表明本次引起GC的原因是因为在年轻代中没有足够的空间能够存储新的数据了。
10258K->6780K(46144K),:单位是KB
三个参数分别为:GC前该内存区域(这里是年轻代)使用容量,GC后该内存区域使用容量,该内存区域总容量。
0.0047613 secs:
该内存区域GC耗时,单位是秒
[Times: user=0.04 sys=0.00, real=0.01 secs]:
分别表示用户态耗时,内核态耗时和总耗时
日志分析2.0版本:
采用在线gceasy来进行分析,我们打开网址,然后上传我们生产的gc日志,如图所示:
优化问题:
列出了可以优化的4个问题新生代和老年代元空间内存占用情况
吞吐量统计:97.39%
各各分代的内存变化:
CMS垃圾收集器不同时期发生的耗时
GC发生次数的分类和耗时情况
定位问题:
我们通过生产的快照文件来定位问题:
JProfiler:
下载到本地通过JProfiler打开查看
查看大对象:
我们不难发现是ArrayList集合占用了96%的内存,那我们来看看哪块代码大量用到了我们ArrayList集合了?
找到对应代码
通过此代码我们就发现put方法大量用到了ArrayList集合造成的内存溢出OOM
总结:
上述实战相信大家都明白了,大致流程就是:
1、够将SpringBoot项目 模拟真实大批量用户场景
2, the configuration parameters are then deployed JVM generate a log file operation monitoring data
3, confirm the problem by analyzing the log files.
Above code and software needs of friends, you can focus on my micro letter: Java2B, you can own practical operation at a deeper impression.
Today wrote this. Like a good feel welcome focus, your attention is my point Like a good text biggest motivation.
This can be seen are the cattle, to help spot trouble at Like a concern, I continue to bring next CMS and G1 combat PK contrast, graphical comparison look more intuitive.
加关注,不迷路。
复制代码