标记-清除
统⼀标记出需要回收的对象,标记完成之后统⼀回收所有被标记的对象,⽽由于标记的过程需要遍历所有的GC ROOT,清除的过程也要遍历堆中所有的对象,所以标记-清除算法的效率低下,同时也带来了内存碎⽚的问题。
复制算法
为了解决性能的问题,复制算法应运⽽⽣,它将内存分为⼤⼩相等的两块区域,每次使⽤其中的⼀块,当⼀块内存使⽤完之后,将还存活的对象拷⻉到另外⼀块内存区域中,然后把当前内存清空,这样性能和内存碎⽚的问题得以解决。但是同时带来了另外⼀个问题,可使⽤的内存空间缩⼩了⼀半!因此,诞⽣了我们现在的常⻅的年轻代+⽼年代的内存结构:Eden+S0+S1组成,因为根据IBM的研究显示,98%的对象都是朝⽣夕死,所以实际上存活的对象并不是很多,完全不需要⽤到⼀半内存浪费,所以默认的⽐例是8:1:1。这样,在使⽤的时候只使⽤Eden区和S0S1中的⼀个,每次都把存活的对象拷⻉另外⼀个未使⽤的Survivor区,同时清空Eden和使⽤的Survivor,这样下来内存的浪费就只有10%了。如果最后未使⽤的Survivor放不下存活的对象,这些对象就进⼊Old⽼年代了。
PS:所以有⼀些初级点的问题会问你为什么要分为Eden区和2个Survior区?有什么作⽤?就是为了节省内存和解决内存碎⽚的问题,这些算法都是为了解决问题⽽产⽣的,如果理解原因你就不需要死记硬背了
标记-整理
针对⽼年代再⽤复制算法显然不合适,因为进⼊⽼年代的对象都存活率⽐较⾼了,这时候再频繁的复制对性能影响就⽐较⼤,⽽且也不会再有另外的空间进⾏兜底。所以针对⽼年代的特点,通过标记-整理算法,标记出所有的存活对象,让所有存活的对象都向⼀端移动,然后清理掉边界以外的内存空间。
网友评论