垃圾回收
java基于内存的动态分配,回收也是自动且动态回收。
因java程序计数器、虚拟机栈、本地方法栈均伴随线程产生而产生,线程销毁而销毁。栈帧的内存基本是类加载后确定的,大多不考虑这部分的内存回收。 而java堆以及方法区不同的是,我们只有在运行时才能知道会创建哪些对象,这部分内存是动态分配的,因而采用动态回收机制。分类
1、引用计数算法
给对象添加一个引用计数器,当对象被一个地方引用,则计数器加一;当引用失效时,计数器减一。当计数器为0时,对象为不可用,需要被清除。
缺点是两个相互引用的对象,虽然对象已无其它引用,但是也不能被清除,GC无法回收它们2、可达性分析算法
使用GC roots 对象作为起点,从该节点向下搜索的路径称为引用链。当对象与GC roots之间没有任何引用链相连时,该对象为不可用。
可以作为GC roots 对象的几种情况:
- 虚拟机栈中引用的对象
- 方法区中常量引用的对象
- 本地方法栈中JNI(native方法)引用的对象
- 方法区中类静态属性引用的对象
引用的分类,该4中分类中引用的强弱递减
1、强引用
是通过new 产生的对象,即Object obj = new Object(),该引用类型引用的对象永远不会被回收。
2、软引用
用于描述非必须但有用的对象,在可能发生内存溢出之前,会将对象列入回收范围。
3、弱引用
用于描述非必需的对象,在下次垃圾回收时,不管内存是否足够,均会清除该类对象。
4、虚引用
最弱的一种引用,无法通过虚引用获取一个对象。
垃圾回收算法
1、标记清除算法
标记清除算法指“标记”和"清除”两个过程,首先对需要回收的对象进行标记,在标记后同一回收所有被标记的对象。 这种算法会产生大量的碎片,导致需要分配较大内存时,不得不提前出发下一次垃圾回收,并且标记和清除两个过程效率较低。2、复制算法
为了解决标记清除算法引出的缺点,复制算法得以出现。 复制算法首先将内存一分为二,每次只用一块,当一块用完了,将还需要使用的对象复制到另一块,然后对已使用的内存进行清理。 这样使得内存可用范围缩小了一半。 目前主流的虚拟机,一般讲内存分为三部分 80%的Eden和两个较小占10%的survivor区,这样分布是基于新生代98%的对象都要回收,所以每次只浪费10%的survivor区域,如果某次回收的对象超过10%,需要依赖其它内存分配担保。3、标记整理算法
当有对象存活率较高时,进行复制操作,效率会降低。针对老年代提出了另一种算法:“标记整理”。
顾名思义,我们先对需要清除的对象进行标记,然后对对象进行整理,使所有对象向一端移动,然后清除边界以外的内存。4、分代收集算法
目前商业主流虚拟机均采用该类算法,根据对象存活周期将内存区域分为几块,在新生代中,对象更新较快,因而选用复制算法。老年代中,对象回收率较高,因而采用“标记-清除”或“标记-整理”算法进行回收。