垃圾回收主要针对的是JVM的堆内存,分为新生代和老年代。
按照以前的叫法,还有一个永久代,它在方法区里保存了class信息、静态变量、常量池等。
这样会使得内存溢出的可能性进一步减小,空间大小变得更容易扩展。
与此同时,方法区也将一部分数据转移了出去,比如类的静态变量、字符串常量池等都放到了堆内存当中。这个变化从1.8后正式开始。
我们平时所讨论的JVM,都是Hopspot版本。刚才提到的永久代,是Hopspot特有的。
在堆内存中,从垃圾回收的范围上说,一般分为两种,新生代的垃圾回收叫Young GC,老年代的垃圾回收通常伴随着新生代的垃圾回收,叫做Full GC。
对垃圾的处理分为搜集算法和回收算法。
垃圾搜集算法
首先需要标记出需要回收的对象,也就是要确定哪些是垃圾。有两种方法,一种叫引用计数法,另一种叫做可达性分析算法。
引用计数法
每个对象都会有一个引用计数器,每当有一个引用指向这个对象的时候,对象的计数器就+1,这样的话,只要观察这个对象的引用计数器,数值>0,就表示还有人在使用,这个对象就不能回收。
当引用计数器=0时,表示没有任何引用指向这个对象,该对象已经不可访问,那么垃圾搜集器就可以回收它。
可达性分析算法
因此,Java使用了一种叫做可达性分析的算法,就是从整个堆内存的根对象出发,看看有多少对象是可达的,有多少是不可达的,无法到达的也就意味着无法访问,自然就是垃圾了。
- 栈中引用的对象(栈)
- 类静态属性引用的对象(方法区)
- 常量引用的对象(方法区)
- native方法引用的对象(本地方法栈)
垃圾回收算法
标记好垃圾之后,就可以回收了,下面介绍3种回收的算法。
标记-清除法
当垃圾回收器将内存扫描之后,会标记出所有垃圾对象,然后将他们回收。
标记-整理法
在清理垃圾的基础上,多了一步碎片整理的工作。
复制算法
准备两块一模一样的内存,当第一块内存空间不足时,将所有需要保留的对象拷贝至另一块内存。
然后将前一块内存直接清空。
缺点:内存空间浪费一倍