一,假如活在一个没有分代的连续内存中
假设程序占用的内存是从0000~FFFF这个地址,现在程序执行到给一个对象分配内存的那部分代码,给这个对象分配了2345~2346这段内存,程序继续执行,到了某一个时刻,程序分配的内存地址用完了,这时候,程序要回收这段地址里面,已经无用的对象,那么,它首先要从头到尾扫描一遍,然后把其中没用的地址空间找到,之后将对象占用地址的起始位置和终止位置进行一个向上或者向下的移动,将不连续的地址变成连续的地址空间,打扫房间结束,程序继续分配内存执行程序;在一整块连续的内存中,进行所有对象的分配,方式是比较简单的,但是就是每次都要从头到尾的扫描一遍,如果程序占用的内存非常大,或者程序需要对外部响应非常及时,这时候,就会出现很大的问题了。
二,two part
将可用内存分为:常回收内存部分+不常回收部分。按照对象是否经常被回收进行分配内存。对象创建之后,先放入常常进行垃圾回收的内存空间中,如果好久不释放,再放入不常回收的部分。需要制定一个标准或者规则,来定义多久对象从常回收部分移动到不常被回收的部分。
这部分主要是为了说明为什么要分代回收。
三,s0,s1 Eden部分
这三部分都属于新生代,对象被创建之后,首先放入Eden中,经过一次Minor GC,被放入From Survivor,再次Minor GC,想象你此时身处From Survivor中,你身边有着经历过16此Minor GC还活着的老对象,它们被移动到了老年代中,还有像你似的,只经历过一两次的,你们一起被复制到了To Survivor中,最后,From Survivor空了,Eden也空了,之后,To Survivor连续整齐的排列着熬下来还属于青年的新生代对象,From Survivor与To进行交换,此时,你又回到了From survivor中,静静地等着下一个时钟周期的到来。。
四,s部分作用
如果没有s部分,每次新创建的对象,先被放到Eden,满了之后,放到老年代,老年代满了,full gc,你会发现,full gc其实是很频繁的,为了不经常对老年代进行回收,就要把年轻代里面对象的回收,做的过程久一点,放入到老年代的条件严格一点儿,所以加入一个中间缓冲带S。
五,s0与s1
试想如果仅有s,在某个对新生代回收的时刻,这时候,在Eden与S部分,都有不连续的内存空间,合并之后,空间还是不连续的,有时候可能会出现这种情况,给一个对象分配空间,总的剩余容量是足够的,但是没有连续的空间可以达到对象的大小,这就尴尬了。所以,为了减少这种碎碎念的出现,s拆分为s0,s1,两部分采用复制算法进行对象交换,保证了在某个时刻,一个s是空的,另一个空间是连续的。