Java自动内存管路主要是针对对象的内存回收和对象的内存分配,其中Java自动内存管理中最核心的就是堆内存中对象的分配和回收
1.引用计数法
给对象中添加以恶搞引用计数器
2.可达性分析算法
这个算法的基本思想就是通过一系列的“GC Roots”的对象作为起点,从这些加点开始向下进行搜索,节点所走过的路径被称为引用链,当一个对象到“GC Roots”没有任何引用链相连的话,则证明此对象是不可用的,需要被回收。
哪些对象可以作为 GC Roots 呢?
3.引用
无论是通过桔树算法判断对象的引用数量,还是通过可达性分析算法判断是否引用链可达,判断对象是否存活都和“引用”离不开关系。
在JDK1.2之前,Java中引用的定义很传统:如果reference类型的数据储存的数字数值代表的是另一块内存的起始地址,就称这块内存代表一个引用。
JDK1.2之后,Java对引用的概念进行了扩充,将引用分为强引用、软引用、弱引用、虚引用四种
判定一个常量是否是“废弃常量”比较简单,而要判定一个类是否是“无用的类”的条件则相对苛刻许多。类需要同时满足下面 3 个条件才能算是 “无用的类” :
1.分代收集理论
当前商业虚拟机的垃圾收集器,大多都遵循了分代收集的理论进行设计,分代收集名为理论,实际是一套符合大多数程序运行实际情况的经验法则,它建立在两个分代假说之上::
1)弱分代假说:绝大多数对象都是朝生夕灭的
2)强分代假说:熬过越多次垃圾收集过程的对象就越难以消亡
这两个分代收集假说奠定了多款常用的垃圾收集器的一致的设计原则:收集器应该将Java堆划分出不同的区域,然后将回收的对象依据其年龄(即熬过垃圾收集过程的次数)分配到不同的区域之中储存,显而易见,如果一个区域中的大多数对象都是朝生夕灭,难以熬过垃圾收集的过程的话,那么九八他们集中在一起,每次回收时只关注如何保留少量存活而不是去标记那些大量的将要被回收的对象,就能以较低的代价回收到大量的空间。
2.标记清除算法
该算法分为标记和清除两部分:首先标记出所有不需要回收的对象,在标记完成后统一回收掉所有没有被标记的对象,它是最基础的收集算法,后续的算法都是对其不足进行改进得到的。这种垃圾收集算法会带来两个明显的问题:
1)效率问题
2)空间问题(标记后会产生大量不连续的碎片)
标记前
如果Java队中包含大量对象,而且其中大部分是需要被回收的,这时必须进行大量的标记和清除的动作,导致标记和清除的效率都随对象数量的增长而降低。
标记删除后
碎片就是多余的白色部分,明明可以放一个很大的对象,但是因为内存空间的不连续,导致内存不够。
解决办法
1.标记整理算法
根据老年代的特点提出来的一种标记算法,标记过程仍然与”标记清除“算法一样,但是后续步骤不是直接对可回收对象进行回收,而是让所有存活的对象向一端移动,然后直接清理到边界以外的内存。
2.标记-复制算法
为了解决效率问题,“标记-复制”收集算法出现了。它可以将内存分为大小相同的两块,每次使用其中的一块。当这一块的内存使用完后,就将还存活的对象复制到另一块去,然后再把使用的空间一次清理掉。这样就使每次的内存回收都是对内存区间的一半进行回收。
这种算法实现简单、运行高效,不过其缺陷也显而易见,这种复制回收算法的d代价是将可用内存缩小为了原来的一半,空间浪费很大。
3.分代收集算法
当前虚拟机的垃圾收集都采用分代收集算法,这种算法没有什么新的思想,只是根据对象存活的周期的不同将内存分为几块。一般将Java堆分为新生代和老年代这样我们就可以根据各个年代的特点选择合适的垃圾收集算法。
例如,在新生代中,每次收集都会有大量的对象死去,所以可以选择标记复制的算法,只需要付出少量对象的复制成本就可以完成每次的垃圾收集,而老年代的对象存活几率是比较高的,而且没有额外的空间对它进行分配担保,所以我们必须选择标记清除或者标记整理的算法吖来进行垃圾回收。