JVM堆内存结构分配

https://blog.csdn.net/u012538947/article/details/51017063

JVM的堆内存分为新生代(Young Generation)和旧生代(Old Generation)。新生代分为Eden区和Survivor区。Survivor区分为From Survivor和To Survivor。如图:

从上图可以看出,新生代通常占JVM堆内存的1/3,因为新生代存储都是新创建的对象,比较小的对象,而老年代存的都是比较大的,活的久的对象,所以老年代占JVM堆内存较大;还可以看出,新生代里的Eden区通常占年轻代的4/5,两个Survivor分别占新生代的1/10。因为Survivor中存储的是GC之后幸存的对象,实际上只有很少一部分会幸存,所以Survivor占的比例比较小。

下面讲解一下当对象A创建之后,对象A在各个区之间的流转过程,也就是各个区作用。

1) 对象A被new出来之后,是被存放在Eden区的。注释:Eden即伊甸园,亚当和夏娃的故事

2) 当发生一次GC之后,Eden区存活下来的对象A会被复制到Survivor 1区(此时Survivor 1为To Survivor);Survivor 0 (此时为From Survivor)中存活的对象也会被复制到Survivor 1中。

3) GC会清空Eden和Survivor 0 (即From Survivor)中存储的所有对象。因为Eden和Survivor 0 中存活的对象都被复制到 Survivor 1中了,所以清空是没问题的。

4) 交换Survivor 0和Survivor 1的角色:即此时有数据的Survivor 1作为From Survivor,被清空的Survivor 0作为To Survivor。要保证在GC发生之前,To Survivor永远是空的那个

5) 下次GC发生时,重复上述步骤。将Eden中存活的对象复制到To Survivor,将From Survivor中活的对象也复制到To Survivor。

扫描二维码关注公众号,回复: 3359151 查看本文章

说到此处,有细心的同学会发现,这都是新生代之间的作用,那老年代呢?

其实是这样的,在上述步骤中,发生GC时,From Survivor中存活的对象并不是全部都会被复制到To Survivor中,而是根据这个对象在Survivor区中存活了多久而决定去向,当一个对象在Survivor中存活了很久(即经历了多次GC还没死),就会在发生GC时被复制到旧生代中。

一个很形象的例子描述对象在JVM堆内存中的生命周期:

我是一个普通的java对象,我出生在Eden区,在Eden区我还看到和我长的很像的小兄弟,我们在Eden区中玩了挺长时间。有一天Eden区中的人实在是太多了,我就被迫去了Survivor区的“To”区,自从去了Survivor区,我就开始漂泊了,因为Survivor的两个区总是交换名字,所以我总是搬家,搬到To Survivor居住,搬来搬去,居无定所。直到我18岁的时候,爸爸说我成人了,该去社会上闯闯了。于是我就去了年老代那边,年老代里,人很多,并且年龄都挺大的,我在这里也认识了很多人。在年老代里,我生活了20年(每次GC加一岁),然后被回收。

还有要理解为什么对象在新生代中复制来复制去的,而不是将死的直接清除,老的直接复制到旧生代?

这样做的好处就是减少了内存碎片,而直接清除的话会使内存很零碎。详情可以了解一下java垃圾回收算法中的复制算法。

猜你喜欢

转载自blog.csdn.net/xiyang_1990/article/details/81712059
今日推荐