1. java堆内存介绍
java的堆内存可以类比于计算机的内存,是存储整个机器数据的地方。
(1)jvm一起动就创建java堆。类比计算机一起动就加载内存。
(2)所有的线程共享。类比计算机所有进程共享一个内存。
(3)是存放实例对象的地方。
2. 堆内存图示
3. 堆内存划分
主要分为年轻代(占堆内存1/3)和老年代(占堆内存2/3)。年轻代又分为eden(占年轻代8/10),from(占年轻代1/10),to(占年轻代1/10)。下面开始分别介绍。
老年代:存储大对象和一些生命周期长的对象。
年轻代:存储占内存少并且生命周期短的对象。
那么问题来了,对象的大小比较好说,直接比较占的空间就行;生命周期长短,这玩意怎么算呢?这就是下面要介绍的eden,from,to
一个对象被new出来之后,是在eden中的。而new对象的操作很频繁,new的对象多了,eden装不下了,就需要对eden进行gc(垃圾回收),发生在eden中的这种小级别的gc叫做minor gc。
4. minor gc(young gc)
先介绍一下eden,from,to
eden:对象出生的地方
from:保存幸存数据的地方
to:空的幸存区
minor gc的过程如下:(参考上图红色的标线)
(1)把eden中活着的对象放到to中,并标记年龄为1。(有一部分可能会被垃圾回收掉)
(2)把from中的活着的对象 age+1(有一部分可能会被垃圾回收掉)。如果age达到阈值(默认15岁),就直接放到老年代中;如果age未达到阈值,就放到to中。
(3)经过步骤(2),to里面保存了存活的对象,from反而清空了。这时候将from和to进行标记切换,from变to,to变from。(备注:当to满了的时候,直接将to里面的数据全部放入老年代)
总结:
minor gc使用复制删除算法,能减少空间碎片。
所有的Minor GC都会停止应用程序的所有线程,不过这个过程非常短暂。
5. major gc(full gc)
采用的是标记-清除算法。
老年代的对象都是程序认为生命力比较顽强的,不是那么容易死掉的,所以没必要频繁的进行full gc。而且老年代的数据比新生代多的多,执行起来也比较耗时。
因为标记清除算法的弊端,会造成很多的内存碎片,当一个大对象进来,没有足够存储他的连续空间的时候,就会执行Full gc。执行完之后就有足够且连续的空间来存放新的对象了。