1.Java堆内存分配
对象根据存活时间被分为:年轻代(Young Generation)、年老代(Old Generation)、永久代(Permanent Generation)。
(1)年轻代
对象被创建时,内存的分配首先发生在年轻代(大对象可以直接被创建在年老代),大部分的对象在创建后很快就不再使用,因此很快就变得不可达,于是被年轻代的GC机制清理掉,这个GC机制被称为Young GC。
注意:Young GC并不代表年轻代内存不足,事实上只表示在Eden区上的GC
年轻代可以分为3个区:Eden(伊甸园,亚当和夏娃偷吃禁果生娃娃的地方,用来表示内存首次分配的区域,再贴切不过了)和2个survivor区。
(2)年老代
对象如果在年轻代存活了足够长的时间而没有被清理掉(即在几次Young GC后存活了下来),则会被复制到年老代,年老代的空间一般比年轻代要大,能存放更多的对象,在年老代上发生GC的次数也比年轻代少。当老年代内存不足时,将执行Full GC
如果对象比较大(如大数组),Young空间不足,则大对象会直接分配到年老代上。
(3)永久代
也就是方法区,主要存储Class信息,和存放对象的堆区不同,GC不会再主程序运行期间对永久代进行清理。如果load很多class,就会有可能出现Permanent Generation space错误
2.GC机制
(1)年轻代
收集算法:
1)绝大多数刚创建的对象会被分配在Eden区,其中的大多数对象很快就会消亡
2)当Eden区满的时候,执行Young GC,将消亡的对象清理掉,并将剩余的对象复制到一个存货区survivor0中(此时survivor1是空白的,两个survivor区总是有一个是空白的)
3)此后,每次Eden区满了,就执行一次Young GC,并将剩余存活的对象都添加到survivor0中
4)当survivor0也满的时候,会将其中仍然存活的对象放入survivor1中,如果survivor1放不下,会将多出来的放入年老区中。以后Eden区执行Young GC之后,就将剩余的对象添加到survivor1中(此时survivor0是空的)
5)当两个存货区切换了若干次(默认为15次)之后,仍然存活的对象将被复制到年老代
(2)老年代
老年代存储的对象比年轻代多的多,而且不乏大对象,对老年代进行内存清理时,一般采用标记-整理方法,即标记出仍然存活的对象,将存活对象向一端移动,以保证内存的连续。
在发生Young GC的时候,虚拟机会检查每次进入老年代的大小是否大于老年代的剩余空间大小,如果大于,则触发一次Full GC。
(3)永久代
包括常量池中的常量回收、无用的类信息回收
注意:
1)Young GC只收集年轻代的对象,Full GC收集所有堆上的对象,包括年轻代、年老代、永久代的对象
2)总而言之,就是分代分配、分代回收
3)System.gc()调用的是Full GC