1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
public class GCLogAnalyzer {
// 在本项目的根目录下有一个gc.log文件,是JVM的GC日志
// 请从中提取GC活动的信息,每行提取出一个GCActivity对象
// 2019-08-21T07:48:17.401+0200: 2.924: [GC (Allocation Failure) [PSYoungGen:
// 393216K->6384K(458752K)] 416282K->29459K(1507328K), 0.0051622 secs] [Times: user=0.02
// sys=0.00, real=0.01 secs]
// 例如,对于上面这行GC日志,
// [PSYoungGen: 393216K->6384K(458752K)] 代表JVM的年轻代总内存为458752,经过GC后已用内存从393216下降到了6384
// 416282K->29459K(1507328K) 代表JVM总堆内存1507328,经过GC后已用内存从416282下降到了29459
// user=0.02 sys=0.00, real=0.01 分别代表用户态消耗的时间、系统调用消耗的时间和物理世界真实流逝的时间
// 请将这些信息解析成一个GCActivity类的实例
// 如果某行中不包含这些数据,请直接忽略该行
public static List<GCActivity> parse(File gcLog) throws IOException {
List<GCActivity> list = new ArrayList<>();
String youngGenRegex = "\\[PSYoungGen:[ ](\\d+)K->(\\d+)K\\((\\d+)K\\)\\]";
String jvmRegex = "[ ](\\d+)K->(\\d+)K\\((\\d+)K\\),";
String timeRegex = "\\[Times:[ ]user=(-?\\d+\\.\\d+?)[ ]sys=(-?\\d+\\.\\d+?),[ ]real=(-?\\d+\\.\\d+?)[ ]secs\\]";
Pattern youngGenGC = Pattern.compile(youngGenRegex);
Pattern jvmGC = Pattern.compile(jvmRegex);
Pattern times = Pattern.compile(timeRegex);
BufferedReader bufferedReader = new BufferedReader(new FileReader(gcLog));
String str = null;
while ((str = bufferedReader.readLine()) != null) {
Matcher matcherYoungGen = youngGenGC.matcher(str);
Matcher matcherJvm = jvmGC.matcher(str);
Matcher matcherTimes = times.matcher(str);
while (matcherYoungGen.find() && matcherJvm.find() && matcherTimes.find()) {
list.add(new GCActivity(
Integer.parseInt(matcherYoungGen.group(1)),
Integer.parseInt(matcherYoungGen.group(2)),
Integer.parseInt(matcherYoungGen.group(3)),
Integer.parseInt(matcherJvm.group(1)),
Integer.parseInt(matcherJvm.group(2)),
Integer.parseInt(matcherJvm.group(3)),
Double.parseDouble(matcherTimes.group(1)),
Double.parseDouble(matcherTimes.group(2)),
Double.parseDouble(matcherTimes.group(3))
));
}
}
return list;
}
public static void main(String[] args) throws IOException {
List<GCActivity> activities = parse(new File("gc.log"));
activities.forEach(System.out::println);
}
public static class GCActivity {
// 年轻代GC前内存占用,单位K
int youngGenBefore;
// 年轻代GC后内存占用,单位K
int youngGenAfter;
// 年轻代总内存,单位K
int youngGenTotal;
// JVM堆GC前内存占用,单位K
int heapBefore;
// JVM堆GC后内存占用,单位K
int heapAfter;
// JVM堆总内存,单位K
int heapTotal;
// 用户态时间
double user;
// 系统调用消耗时间
double sys;
// 物理世界流逝的时间
double real;
public GCActivity(
int youngGenBefore,
int youngGenAfter,
int youngGenTotal,
int heapBefore,
int heapAfter,
int heapTotal,
double user,
double sys,
double real) {
this.youngGenBefore = youngGenBefore;
this.youngGenAfter = youngGenAfter;
this.youngGenTotal = youngGenTotal;
this.heapBefore = heapBefore;
this.heapAfter = heapAfter;
this.heapTotal = heapTotal;
this.user = user;
this.sys = sys;
this.real = real;
}
@Override
public String toString() {
return "GCActivity{"
+ "youngGenBefore="
+ youngGenBefore
+ ", youngGenAfter="
+ youngGenAfter
+ ", youngGenTotal="
+ youngGenTotal
+ ", heapBefore="
+ heapBefore
+ ", heapAfter="
+ heapAfter
+ ", heapTotal="
+ heapTotal
+ ", user="
+ user
+ ", sys="
+ sys
+ ", real="
+ real
+ '}';
}
public int getYoungGenBefore() {
return youngGenBefore;
}
public int getYoungGenAfter() {
return youngGenAfter;
}
public int getYoungGenTotal() {
return youngGenTotal;
}
public int getHeapBefore() {
return heapBefore;
}
public int getHeapAfter() {
return heapAfter;
}
public int getHeapTotal() {
return heapTotal;
}
public double getUser() {
return user;
}
public double getSys() {
return sys;
}
public double getReal() {
return real;
}
}
}
|