目录
概述
相关文章在此总结如下:
文章 | 地址 |
---|---|
jvm基本知识 | 地址 |
jvm类加载系统 | 地址 |
双亲委派模型与打破双亲委派 | 地址 |
运行时数据区 | 地址 |
运行时数据区-字符串常量池、程序计数器、直接内存 | 地址 |
对象的创建流程
常量池检查: 检查 new 指令是否能在 常量池中定位到这个类的符号引用,检查类之前是否被加载过。
分配内存空间:
- 指针碰撞:GC 不带压缩功能,Serial和ParNew
- 空闲列表:GC 带压缩功能,CMS
必要信息设置: 对象类的元数据、对象哈希码、GC分代年龄 ---> 对象头
对象的内存分配方式
内存分配的方法有两种:
- 指针碰撞 (Bump the Pointer)
- 空间列表 (Free List)
分配方法 | 说明 | 收集器 |
---|---|---|
指针碰撞(Bump the Pointer) | 内存地址是连续的(新生代) | Serial和ParNew收集器 |
空闲列表(Free List) | 内存地址不连续(老年代) | CMS收集器和Mark-Sweep收集器 |
对象怎样才会进入老年代
空间担保机制: 当新生代无法分配内存的时候,要想将新生代的对象转移至老年代,然后将新对象放入腾空的新生代。此种机制称之为内存担保
。
对象进入老年代如下:
- 新对象大多数默认都进入
Eden
- 对象进入老年代的四种情况
- 年龄太大
MinorGC15
[-XX:MaxTenuringThreshold] - 动态年龄判断:MinorGC后会动态判断年龄,将符合要求对象番移入老年代
- 大对象直接进入老年代
1M
[-XX:PretenureSizeThreshold] - MinorGC后存活对象太多无法放入
Survivor
- 年龄太大
动态年龄判断:例子,Survivor 区中有一批对象,年龄分别为 年龄1+年龄2+年龄n的多个对象 ,对象总和大小超过了Survivor
区域的 50%
,此时就会将年龄n及以上的对象都放入老年代。
大对象直接进入老年代
测试代码如下:
java
/**
* -XX:NewRatio=2 新生代与老年代比值
* -XX:SurvivorRatio=8 新生代中,Eden 与两个Survivor 区域比值
* -XX:+PrintGcDetails 打印详细 GC 日志
* -XX:PretenureSizeThreshold 对象超过多大值直接在老年代分配,默认值为0,不限制
*/
public class YoungOldArea {
public static void main(String[] args) {
// 分配 20M
byte[] bytes = new byte[1024 * 1024 * 20];
}
}
bash
appledeMacBook-Pro:gc hyl$ javac /Users/hyl/Desktop/jk/jvm/YoungOldArea.java
appledeMacBook-Pro:gc hyl$ cd /Users/hyl/Desktop/jk/jvm
appledeMacBook-Pro:jvm hyl$ java -Xmx60m -Xms60m -XX:NewRatio=2 -XX:SurvivorRatio=8 -XX:+PrintGCDetails YoungOldArea
内存担保
测试代码如下:
java
/**
* 内存分配担保案例
*/
public class MemoryAllocationGuarantee {
private static final int _1MB = 1024 * 1024;
public static void main(String[] args) {
memoryAllocation();
}
public static void memoryAllocation() {
byte[] allocation1, allocation2, allocation3, allocation4;
allocation1 = new byte[1 * _1MB];
allocation2 = new byte[1 * _1MB];
allocation3 = new byte[1 * _1MB];
allocation4 = new byte[5 * _1MB];
System.out.println("完毕");
}
}
bash
appledeMacBook-Pro:jvm hyl$ javac MemoryAllocationGuarantee.java
appledeMacBook-Pro:jvm hyl$ ls
MemoryAllocationGuarantee.class MemoryAllocationGuarantee.java YoungOldArea.class YoungOldArea.java lib
appledeMacBook-Pro:jvm hyl$ java -Xmx20m -Xms20m -XX:NewRatio=2 -XX:SurvivorRatio=8 -XX:+UseSerialGC -XX:+PrintGCDetails MemoryAllocationGuarantee
[GC (Allocation Failure) [DefNew: 3749K->279K(6144K), 0.0039312 secs] 3749K->3351K(19840K), 0.0039781 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
完毕
Heap
def new generation total 6144K, used 5561K [0x00000007bec00000, 0x00000007bf2a0000, 0x00000007bf2a0000)
eden space 5504K, 95% used [0x00000007bec00000, 0x00000007bf128920, 0x00000007bf160000)
from space 640K, 43% used [0x00000007bf200000, 0x00000007bf245d48, 0x00000007bf2a0000)
to space 640K, 0% used [0x00000007bf160000, 0x00000007bf160000, 0x00000007bf200000)
tenured generation total 13696K, used 3072K [0x00000007bf2a0000, 0x00000007c0000000, 0x00000007c0000000)
the space 13696K, 22% used [0x00000007bf2a0000, 0x00000007bf5a0030, 0x00000007bf5a0200, 0x00000007c0000000)
Metaspace used 2668K, capacity 4486K, committed 4864K, reserved 1056768K
class space used 287K, capacity 386K, committed 512K, reserved 1048576K
appledeMacBook-Pro:jvm hyl$
当新生代无法分配内存的时候,要想将新生代的对象转移至老年代,然后将新对象放入腾空的新生代。
注意: jdk8 设置了 使用 SerialGC ,默认GC不是这样的流程,如下命令行执行的命令
bash
appledeMacBook-Pro:jvm hyl$ java -Xmx20m -Xms20m -XX:NewRatio=2 -XX:SurvivorRatio=8 -XX:+PrintGCDetails MemoryAllocationGuarantee
完毕
Heap
PSYoungGen total 6144K, used 3764K [0x00000007bf980000, 0x00000007c0000000, 0x00000007c0000000)
eden space 5632K, 66% used [0x00000007bf980000,0x00000007bfd2d180,0x00000007bff00000)
from space 512K, 0% used [0x00000007bff80000,0x00000007bff80000,0x00000007c0000000)
to space 512K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007bff80000)
ParOldGen total 13824K, used 5120K [0x00000007bec00000, 0x00000007bf980000, 0x00000007bf980000)
object space 13824K, 37% used [0x00000007bec00000,0x00000007bf100010,0x00000007bf980000)
Metaspace used 2668K, capacity 4486K, committed 4864K, reserved 1056768K
class space used 287K, capacity 386K, committed 512K, reserved 1048576K
jvc 相关指令
查看jdk默认使用的gc
bash
java -XX:+PrintCommandLineFlags -version
查看当前jdk支持的有哪些gc
bash
java -XX:+PrintFlagsFinal -version | grep 'bool Use' | grep 'GC ' | grep -v java
查看指定进程当前正在使用的gc
bash
jhsdb jmap --heap --pid 22397
结束
至此,jvm
中对象创建流程与内存分配就结束了,如有疑问,欢迎评论区留言。