jvm性能调优 - 05对象在JVM内存中的分配和流转

在这里插入图片描述


前文回顾

经过上一篇文章铺垫了一些对象分配的基础知识后,想必大家现在都心里非常有数了,咱们平时代码里创建出来的对象,一般就是两种:

  • 一种是短期存活的,分配在Java堆内存之后,迅速使用完就会被垃圾回收

  • 另外一种是长期存活的,需要一直生存在Java堆内存里,让程序后续不停的去使用

第一种短期存活的对象,是在Java堆内存的新生代里的。第二种长期存活的对象,是在Java堆内存的老年代里的。这个结论,想必大家都已经理解了

好,那么接下来我们就来聊聊,对象到底什么时候进入新生代?然后什么情况下会进入老年代?


大部分正常对象都优先在新生代分配内存

首先我们先来看上篇文章中的一段代码,稍微带着大家来理解一个概念:大部分的正常对象,都是优先在新生代分配内存的。

在这里插入图片描述

虽然我们看代码知道,类静态变量“fetcher”引用的那个“ReplicaFetcher”对象,是会长期存活在内存里的

但是哪怕是这种对象,其实刚开始你通过“new ReplicaFetcher()”代码来实例化一个对象时,他也是分配在新生代里的。

包括在“loadReplicasFromDisk()”方法中创建的“ReplicaManager”实例对象,也都是一样分配在新生代里的

同样,我们以一张图,来展示一下:

在这里插入图片描述


到底什么情况下会触发新生代的垃圾回收?

现在咱们来假设一个场景,大家应该都知道,一旦“loadReplicasFromDisk()”方法执行完毕之后,这个方法的栈帧出栈,会导致没有任何局部变量引用那个“ReplicaManager”实例对象了。

此时可能会如下图所示:

在这里插入图片描述

那么此时就一定会立即发生垃圾回收,去回收掉Java堆内存里那个没人使用的“ReplicaManager”实例对象吗?

NO

大家别想的那么简单了,实际上垃圾回收他也得有点触发的条件。

其中一个比较常见的场景可能是这样的,假设我们写的代码中创建了N多对象,然后导致Java堆内存里囤积了大量的对象。

然后这些对象都是之前有人引用,比如各种各样的方法中的局部变量,但是现在也都没人引用了。

如下图所示

在这里插入图片描述

这个时候,如果新生代我们预先分配的内存空间,几乎都被全部对象给占满了!此时假设我们代码继续运行,他需要在新生代里去分配一个对象,怎么办?发现新生代里内存空间都不够了!

这个时候,就会触发一次新生代内存空间的垃圾回收,新生代内存空间的垃圾回收,也称之为“Minor GC”,有的时候我们也叫“Young GC”,他会尝试把新生代里那些没有人引用的垃圾对象,都给回收掉。

比如上图中,那个“ReplicaManager”实例对象,其实就是没有人引用的垃圾对象

此时就会当机立断,把“ReplicaManager”实例对象给回收掉,腾出更多的内存空间,然后放一个新的对象到新生代里去。

包括上图中那大量的实例对象,其实也都没人引用,在这个新生代垃圾回收的过程中,就会把这些垃圾对象也都回收掉。

其实话说回来,大家自己仔细回忆一下,我们在代码中创建的大部分对象,其实都是这种使用之后立马就可以回收掉的生存周期极短的对象,是不是?

可能我们会在新生代里分配大量的对象,但是使用完之后立马就没人引用了,此时新生代差不多满了

然后要分配新的对象的时候,发现新生代内存空间不足,就会触发一次垃圾回收,然后就把所有垃圾对象给干掉,腾出大量的内存空间

如下图所示:

在这里插入图片描述


长期存活的对象会躲过多次垃圾回收?

接着我们来看下一个问题,上图中大家都注意到了“ReplicaFetcher”实例对象,他是一个长期被“Kafka”类的静态变量“fetcher”引用的长期存活的对象。

所以虽然你的新生代可能随着系统的运行,不停的创建对象,然后让新生代变满,接着垃圾回收一次,大量对象被回收掉

但是你的这个“ReplicaFetcher”对象,他确是一直会存活在新生代里的。

因为他一直被“Kafka”类的静态变量给引用了,所以他不会被回收。那么此时JVM就有一条规定了

如果一个实例对象在新生代中,成功的在15次垃圾回收之后,还是没被回收掉,就说明他已经15岁了。

这是对象的年龄,每垃圾回收一次,如果一个对象没被回收掉,他的年龄就会增加1。

所以如果上图中的那个“ReplicaFetcher”对象在新生代中成功躲过10多次垃圾回收,成为一个“老年人”,那么就会被认为是会长期存活在内存里的对象。

然后他会被转移到Java堆内存的老年代中去,顾名思义,老年代就是放这些年龄很大的对象。

我们再来看一张图:

在这里插入图片描述


老年代会垃圾回收吗?

接着下一个问题就是,老年代里的那些对象会被垃圾回收吗?

答案是肯定的,因为老年代里的对象也有可能随着代码的运行,不再被任何人引用了,就需要被垃圾回收。

大家可以思考一下,如果随着类似上面的情况,越来越多的对象进入老年代,一旦老年代也满了,是不是就要对老年代垃圾回收了?

没错,这是肯定的,但是暂时我们先不用过多的去考虑这里的细节,后面我们会进行深入剖析。


关于新生代和老年代的对象分配,这就完了吗?

还有人会说,关于新生代和老年代的对象分配,这就结束了吗?

当然不是,我们这里仅仅是相较于之前的文章,更进一步给大家分析了一下对象分配的一些机制。

但是其实在对象分配这块,还有很多其他的复杂机制,比如:

  • 新生代垃圾回收之后,因为存活对象太多,导致大量对象直接进入老年代

  • 特别大的超大对象直接不经过新生代就进入老年代

  • 动态对象年龄判断机制

  • 空间担保机制

这部分内容结合案例,结合真实生产问题,把JVM各种底层细节带出来。

到这里 ,大家对对象内存分配,了解到这个程度就行了,给大家总结一下:

  • 先理解对象优先分配在新生代

  • 新生代如果对象满了,会触发Minor GC回收掉没有人引用的垃圾对象

  • 如果有对象躲过了十多次垃圾回收,就会放入老年代里

  • 如果老年代也满了,那么也会触发垃圾回收,把老年代里没人引用的垃圾对象清理掉

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小小工匠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值