GCRoot指被栈上直接或间接引用的对象,或被本地方法栈直接或间接引用的对象,或被方法区引用的对象。
被引用的对象是不能被删除的。
如果对象跟GCRoot并没有直接或间接相连的关系,那么这些对象就可以被删除了。
标记-清理:将需要删除的对象标记一下,标记完了再扫描一遍,把含有标记的对象删掉。缺点:内存碎片
标记-整理:在清除这个位置的垃圾之后,后面的对象要补上来。缺点:对象前移,代价大
复制:将内存一分为二,假设叫一区,二区。首先在一区创建这些对象,然后去打标记,标记是否需要被删除,等到一区快满了的时候,并不将标记对象删除,而是将不需要删除的对象复制到二区,并且是紧凑复制,这样避免了内存碎片,需要删除的就不复制到二区了。这样开销也不大,因为每次只需要复制一个对象,不需要移动所有对象。缺点:2倍内存
GC过程是怎样的呢?
Young区:
对象都会在E区出生,当E区快满的时候就会触发GC,这个GC只是Young区域的GC,所以也叫Young GC。
Young GC采用复制算法,当E区快满的时候会把需要删除的对象打上标记,不需要删除的依次复制到S0区。
两块S区是交替工作的。等到E区快满了之后,对E区对象进行打标,将不需要删除的对象复制到S0区,之后将E区和S1区的对象全部删除。
等下次E区快满了之后,再将S0区和E区的对象全部打标,将不需要删除的对象全部复制到S1区。
S0和S1交替使用作为幸存下来的区域,它比直接将内存一分为二的利用率高一些。
E+S1复制到S0,E+S0复制到S1,E+S1复制到S0,… 如此往复
Old区:
每一次Young GC,如果对象活下来了,它的年龄就会加1,直到它满了6岁,就不往S区复制了,直接到Old区了。原因是如果一个对象6次Young GC都没清理掉,那它可能存在很长一段时间,直接把它放到Old区来维护,省的每次都在S区复制了。
Old区除了存一些年龄大的对象,还会存一些大对象,大对象指的是对象占用的内存大。
等到Old区快满了,也会触发GC,这个GC叫做Old GC,Old GC同时会伴随着Young GC,所以它又叫Full GC。Full GC会引起 Stop The World,Stop The World就是整个Java程序暂停,全力的来进行垃圾回收,垃圾回收主要使用标记-清理 或 标记-整理 的算法。
现在我们明确了,标记-清理、标记-整理 主要用于Full GC,复制 主要用于Young GC。
年轻代比较有名的垃圾收集器是ParNew,老年代是CMS,他们分别用了复制算法和标记-清理算法来进行垃圾回收。新版的jdk已经不建议用以前的垃圾收集器了,而是使用了全新的G1垃圾收集器