- 基础知识:
JVM中的实例化对象是存储在heap中的,heap分为,新生代和年长代,新生代又分为(eden、survivor1、survivor0),年长代又称作tenured space,存放经历多次minor gc回收以后,仍然存活的对象,方法区又称为永久区,用于存放class meta相关的全限定类名、方法名、修饰符、常量、参数类型、类成员变量等,这些基础知识相信大家并不陌生,本文主要介绍的是创建一个对象,对JVM存储产生的变化。
- 存储分析
根据以上基础知识,得出结论:
1、创建一个对象会增加heap区的存储占用
2、如果创建的多个实例,同属同一个class,由于是属于同一个class,所以对PermGen即永久区不会产生影响
论证的流程如下:
1、创建一个名为Jvm的自定义类对象,完成后,观察heap区和PermGen的占用,获取此时的存活对象的个数和占用字节数
2、创建1000个名为Jvm的自定义对象,完成后,观察heap区和PermGen的占用,获取此时的存活对象的个数和占用字节数
3、拿两次heap区和PermGen的已用内存变动做差值比较,多出来的存储内容,理论上就是由多创建出的999个JVM对象产生的
4、拿两次存活对象占用空间做差值比较,得出的差值==两次heap区的已用内存的差值
5、以上的两次采集的内容,需要保证:
5.1、heap已用内存的占用采样和收集到的对象个和占用空间的采样必须保证是在Jvm对象创建完毕以后进行采集
5.2、收集到的对象必须是保证全部是存活对象
如上5.1的条件比较容易实现,只需要在自定义类Jvm的全部实例化完成后,调用jmap -heap获取当前的堆存储情况即可,保证5.2的条件方式有两种:
5.2.1一种是使用jmap -histo:live,这种方式在目前的场景下有个缺陷是,执行完这个命令会触发fullgc、这样会导致本次测试用例中的Jvm实例强制回收,这样会出现统计出的heap是包含自定义对象的存储占用,而统计出的对象则不包含自定义对象,所以考虑采用5.2.2方式
5.2.2统计出所有对象的个数和占用比使用jmap -heap命令,增加附加条件,保证在此期间不发生GC,使用jstat -gcutil进行监控GC情况
- 验证过程
先上测试代码:
1、自定义Class
package com.tt.st.jvm;
public class Jvm {
}
2、Main
package com.tt.st.jvm;
import java.util.ArrayList;
import java.util.List;
public class Main {
private List<Jvm> list = new ArrayList<>();
public static void main(String[] args) throws Exception {
Main main = new Main();
int k = Integer.parseInt(args[0]);
main.ok(k);
}
private void ok(int k) throws Exception{
for(int j=1;j<=k;j++) {
Jvm jvm = new Jvm();
list.add(jvm);
}
System.out.println("init complete");
Thread.sleep(10*1000l);
}
}
3、执行脚本liveClc.sh:
pid=$(ps -ef | grep java | awk 'NR==1 {print $2}')
jmap -heap $pid >>b.txt
jmap -histo $pid >>c.txt
jstat -gcutil $pid>>e.txt
4、执行命令:
4.1、java -Xms2m -Xmx2m com/tt/st/jvm/Main 1000
4.2、./liveClc.sh
4.3、java -Xms2m -Xmx2m com/tt/st/jvm/Main 1
4.4、./liveClc.sh
5、差值比较:
Heap Configuration:
MinHeapFreeRatio = 0
MaxHeapFreeRatio = 100
MaxHeapSize = 8388608 (8.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 = 2097152 (2.0MB)
used = 428528 (0.4086761474609375MB)
free = 1668624 (1.5913238525390625MB)
20.433807373046875% used
From Space:
capacity = 524288 (0.5MB)
used = 0 (0.0MB)
free = 524288 (0.5MB)
0.0% used
To Space:
capacity = 524288 (0.5MB)
used = 0 (0.0MB)
free = 524288 (0.5MB)
0.0% used
PS Old Generation
capacity = 1048576 (1.0MB)
used = 0 (0.0MB)
free = 1048576 (1.0MB)
0.0% used
PS Perm Generation
capacity = 22020096 (21.0MB)
used = 2701672 (2.5765151977539062MB)
free = 19318424 (18.423484802246094MB)
12.269119989304315% used
Heap Configuration:
MinHeapFreeRatio = 0
MaxHeapFreeRatio = 100
MaxHeapSize = 8388608 (8.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 = 2097152 (2.0MB)
used = 381192 (0.36353302001953125MB)
free = 1715960 (1.6364669799804688MB)
18.176651000976562% used
From Space:
capacity = 524288 (0.5MB)
used = 0 (0.0MB)
free = 524288 (0.5MB)
0.0% used
To Space:
capacity = 524288 (0.5MB)
used = 0 (0.0MB)
free = 524288 (0.5MB)
0.0% used
PS Old Generation
capacity = 1048576 (1.0MB)
used = 0 (0.0MB)
free = 1048576 (1.0MB)
0.0% used
PS Perm Generation
capacity = 22020096 (21.0MB)
used = 2701672 (2.5765151977539062MB)
free = 19318424 (18.423484802246094MB)
12.269119989304315% use
5.1永久区差值:Perm2-Perm1=2701672 -2701672 =0
5.2堆区的差值:heap2-heap1=428528 -381192=47336
5.3保证采集到的对象个数是在无GC发生的情况下:
S0 S1 E O P YGC YGCT FGC FGCT GCT
0.00 0.00 22.44 0.00 12.27 0 0.000 0 0.000 0.000
S0 S1 E O P YGC YGCT FGC FGCT GCT
0.00 0.00 20.18 0.00 12.27 0 0.000 0 0.000 0.000
5.4采集对象占用空间比较,由于内容较多,只选取差异的部分
num #instances #bytes class name
204: 1 16 com.tt.st.jvm.Jvm
15: 1000 16000 com.tt.st.jvm.Jvm
14: 326 14208 [Ljava.lang.Object;
12: 338 29152 [Ljava.lang.Object;
6: 1354 128880 [C
6: 1354 128888 [C
8: 13 105880 [I
7: 14 122280 [I
sumbytes2-sumbytes1=47336
5.5、heap的差值=存活对象的差值