对象的整个生命周期

1.对象的创建过程

1.类加载检测

量池中定位到一个类的符号引用,同时并检查这个符号引用代表的类是否被加载解析初始化过。

没有就会走双亲委派机制,进行类加载

2.内存分配

在栈上分配-TLAN上分配-是否符合老年代要求-新生代

栈上分配是属于C2编译器的激进优化,建立在逃逸分析的基础上,使用标量替换拆解聚合量,以基本量代替对象,然后最终做到将对象拆散分配在虚拟机栈的局部变量表中,从而减少对象实例的产生,减少堆内存的使用以及GC次数。

TLAB全称叫做Thread Local Allocation Buffer,是指JVM在Eden区为每条线程划分的一块私有缓冲内存。在上篇对于JVM内存区域分析的文章中曾分析到:大部分的Java对象是会被分配在堆上的,但也说到过堆是线程共享的,那么此时就会出现一个问题:当JVM运行时,如果出现两条线程选择了同一块内存区域分配对象时,不可避免的肯定会发生竞争,这样就导致了分配速度下降

初次分配时,大对象直接进入年老代。
一般对象进入年老代的情况只有三种:大对象、长期存活对象以及动态年龄判断符合条件的对象,在JVM启动的时候你可以通过-XX:PretenureSizeThreshold参数指定大对象的阈值,如果对象在分配时超出这个大小,会直接进入年老代

不同的GC器对于大对象的判定标准也不一样

新生代分配
1.指针碰撞:一般适用于Serial、ParNew等不会产生内存碎片、堆内存完整的的垃圾收集器。

2.空闲列表:与指针碰撞一样,空闲列表同样是Java在为新对象分配堆内存时的一种内存分配方式,一般适用于CMS等一些会产生内存碎片、堆内存不完整的垃圾收集器。

3.初始化内存

初始化分配到的这块空间,JVM会将分配到的内存空间(不包括对象头)都初始化为零值,这样做的好处在于:可以保证对象的实例字段在Java代码中不赋初始值就直接使用,程序可以访问到字段对应数据类型所对应的零值,避免不赋值直接访问导致的空指针异常。

4.对象头设置

将对象的原始哈希码、GC年龄、锁标志、锁信息组装成MrakWord放入对象头中,然后会将指向当前对象类元数据的类型指针KlassWord也加入对象头中,如果当前对象是数组对象,那么还会将编码时指定的数组长度ArrayLength放入对象中,最终当对象头中的所有数据全部组装完成后,会将该对象头放在对象分配的内存区域中存储。

5.初始化

执行<init>函数,也就是构造函数,主要是对属性进行显式赋值。

2.GC时的对象移动与对象晋升

判断这个对象是否还存在引用

1.GC时刻

当对象移动一次,那么对象头内MrakWord中的对象年龄则会+1(刚创建的对象年龄为0)。而大部分的分代GC器中,对于老年代的晋升标准默认为15岁(CMS为8岁),也就是当对象来回移动16次之后,这些依旧存活的对象会被转入年老代存储,可以通过参数-XX:MaxTenuringThreshold更改年龄阈值。

2.动态对象年龄判断

如果在Survivor区中相同年龄的所有对象大小总和大于Survivor空间的一半,那么Survivor区中所有大于或等于该年龄的对象就可以直接进入年老代,无需等到满足阈值的标准后再晋升,这种晋升方式也被称为JVM的动态对象年龄判定。

3.空间分配担保机制

发生GC时,一个S区空间无法储存Eden区和另外一个S区的存活对象时,这些对象会被直接转移到年老代,这个过程就是空间分配担保。在进行MinorGC前,如果老年代的连续空间大于新生代对象大小总和或历次晋升的平均大小,如果大于,则此次MinorGC是安全的,则进行MinorGC,否则进行先FullGC

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值