为什么要区分年轻代和老年代呢?
年轻代里存放的大多数对象是短期存活的对象,需要用复制回收算法。老年代里存放的对象是长期存活的对象,用的是标记-整理算法。所以才需要区分年轻代和老年代。
一种不太好的回收思路
思路:标记出哪些对象是可以被GC的,然后直接将那块内存区域的对象进行GC。
这样的话,对象会在内存中东一个西一个,造成大量的内存碎片。虽然所有的内存碎片加起来是很大的一块内存,但是它们都是碎片式分散的,所以导致没有一块完整的足够的内存区域来分配对象,从而造成内存浪费。
初步的复制回收算法
1.我们将新生代的内存切分为两块
2.标记哪些对象是不能被GC的,将这些对象转移到另一块空白的内存区域,因此这些对象都可以紧凑的有序的排列在内存中,不存在内存碎片的问题。
3.一次性把原来使用的那块内存中的垃圾对象全部清除掉,空出来一块内存区域
4.两块内存区域这么重复循环使用着
存在的问题:对内存的使用率太低了,假设我们给新生代分配1G的内存空间,实际上也就只有512MB的内存空间是可以用的
复制算法的优化:Eden和Survivor区
其实绝大多数对象是存活周期非常短的对象,可能一次新生代GC后,99%的对象都被垃圾回收了,可能也就1%的对象存活下来。由于这个特性,所以就设计了留10%的新生代内存空间来存放一次GC后存活的对象
将新生代内存分为3块区域,1个Eden区(占80%的空间),2个Survivor区(每个Survivor区占10%)。平时可以使用的,就是一个Eden和一个Survivor,相当于有90%得内存空间可以使用,而另一个Survivor区使用来存放上一次GC后存活的对象。
刚开始对象都是在Eden区中分配的,如果Eden快满了,就触发GC。此时会把Eden区中存活的对象一次性转移到一块空着的Survivor区,接着Eden区全部清空,然后再次分配新对象到Eden区。
如果下次再发生MinorGC,就会把Eden区和放着上次存活对象的Survivor区中的存活对象转移到另一块空的Survivor区中,再一次性把Eden区和之前使用的Survivor区全部清空。然后一直循环往复。
最大的好处是,垃圾回收性能好,无内存碎片,内存的使用率高。