程序员自己做网站怎么能来钱,白云网站开发,厦门seo排名优化公司,网站推广计划至少包括垃圾回收
在 JVM 中需要对没有被引用的对象#xff0c;也就是垃圾对象进行垃圾回收
对象存活判断算法
判断对象存活有两种方式#xff1a;引用计数法、可达性分析算法
引用计数法
引用计数法通过记录每个对象被引用的次数#xff0c;例如对象 A 被引用 1 次#xff0c…垃圾回收
在 JVM 中需要对没有被引用的对象也就是垃圾对象进行垃圾回收
对象存活判断算法
判断对象存活有两种方式引用计数法、可达性分析算法
引用计数法
引用计数法通过记录每个对象被引用的次数例如对象 A 被引用 1 次就将 A 的引用计数器加 1当其他对象对 A 的引用失效了就将 A 的引用计数器减 1
优点 实现简单判定效率高 缺点 需要单独的字段存储计数器增加存储空间开销每次赋值都要更新计数器增加时间开销无法处理循环引用的情况致命问题即 A 引用 BB 引用 A那么他们两个的引用计数器永远都为 1
可达性分析算法
可达性分析算法可以有效解决循环引用的问题Java 选择了这种算法
可达性分析算法以根对象集合GC Roots为起使点按照从上至下的方式搜索被根对象集合所连接的目标对象是否可达通过可达性分析算法分析后内存中的存活对象都会被根对象集合直接或间接连接着搜索过程所走过的路径称为引用链如果目标对象没有任何引用链相连则是不可达的就可以标记为垃圾对象
GC Roots 主要包含以下几类元素 虚拟机栈中引用的对象 如各个线程被调用的方法中所使用的参数、局部变量等 本地方法栈内的本地方法引用的对象 方法区中引用类型的静态变量 方法区中常量引用的对象 如字符串常量池里的引用 所有被 synchronized 持有的对象 Java 虚拟机内部的引用 如基本数据类型对应的 Class 对象、异常对象如 NullPointerException、OutOfMemoryError、系统类加载器
垃圾回收过程
在 Java 中对垃圾对象进行回收需要至少经历两次标记过程
第一次标记如果经过可达性分析后发现没有任何引用链相连则会第一次被标记第二次标记判断第一次标记的对象是否有必要执行 finalize() 方法如果在 finalize() 方法中没有重新与引用链建立关联则会被第二次标记
第二次被标记成功的对象会进行回收否则将继续存活
对象的 finalization 机制
Java 提供了 finalization 机制来允许开发人员 自定义对象被销毁之前的处理逻辑即在垃圾回收一个对象之前会先调用这个对象的 finalize() 方法该方法允许在子类中被重写用于在对象被回收时进行资源释放的工作
对象引用
在 JDK1.2 之后Java 对引用的概念进行了扩张将引用分为强引用StrongReference、软引用SoftReference、弱引用WeakReference、虚引用PhantomReference四种这四种引用强度依次逐渐减弱 强引用-不回收强引用是最普遍的对象引用也是默认的引用类型强引用的对象是可触及的垃圾回收器永远不会回收被引用的对象因此强引用是造成Java内存泄漏的主要原因之一。 当使用new操作创建一个新对象时并且将其赋值给一个变量时这个变量就成为该对象的一个强引用 软引用-内存不足回收在即将发生内存溢出时会将这些对象列入回收范围进行第二次回收如果回收之后仍然没有足够的内存则会抛出内存溢出异常 软引用通常用来实现内存敏感的缓存例如高速缓存使用了软引用如果内存足够就暂时保留缓存如果内存不足就清理缓存 // 创建弱引用
SoftReferenceUser softReference new SoftReference(user);
// 从软引用中获取强引用对象
System.out.println(softReference.get());弱引用-发现即回收被弱引用关联的对象只能存活在下一次垃圾回收之前在垃圾回收时无论空间是否足够都会会受掉被弱引用关联的对象 弱引用常用于监控对象是否已经被垃圾回收器标记为即将回收的垃圾可以通过弱引用的 isEnQueued 方法判断对象是否被垃圾回收器标记 Object obj new Object();
WeakReferenceObject wf new WeakReferenceObject(obj);
obj null;
// System.gc();
// 有时候会返回null
Object o wf.get();
// 返回是否被垃圾回收器标记为即将回收的垃圾
boolean enqueued wf.isEnqueued();
System.out.println(o o);
System.out.println(enqueued enqueued);虚引用垃圾回收时直接回收无法通过虚引用获取对象实例 为一个对象设置虚引用关联的唯一目的就是能在这个对象被垃圾回收时收到一个系统通知 Object obj new Object();
PhantomReferenceObject pf new PhantomReferenceObject(obj, new
ReferenceQueue());
objnull;
// 永远返回null
Object o pf.get();
// 返回是否从内存中已经删除
boolean enqueued pf.isEnqueued();
System.out.println(o o);
System.out.println(enqueued enqueued);垃圾清除算法
GC最基础的算法有三种 标记 -清除算法、复制算法、标记-压缩算法我们常用的垃圾回收器一般都采用分代收集算法。 标记-清除算法在标记阶段从 GC Roots 开始遍历标记所有被引用的对象标记为可达对象再对堆内存从头到尾遍历回收没有标记为可达对象的对象标记清除算法可以标记存活对象也可以标记待回收对象 这里并不是真正清除而是将清除对象的地址放在空闲的地址列表中缺点 效率不高GC 时需要停止整个应用进程用户体验不好会产生内存碎片 复制算法它将可用内存按容量划分为大小相等的两块每次只使用其中的一块。当这一块的内存用完了就将还存活着的对象复制到另外一块上面然后再把已使用过的内存空间一次清理掉 现在商用的 Java 虚拟机大多都优先采用这种收集算法去回收新生代如果将内存区域划分为容量相同的两部分太占用空间因此将复制算法进行了优化优化后将新生代分为了 Eden 区、Survivor From 区、Survivor To 区Eden 和 Survivor 的大小比例为 8:1:1每次分配内存时只使用 Eden 和其中的一块 Survivor 区在进行垃圾回收时将 Eden 和已经使用过的 Survivor 区的存活对象转移到另一块 Survivor 区中再清理 Eden 和已经使用过的 Survivor 区域当 Survivor 区域的空间不足以容纳一次 Minor GC 之后存活的对象时就需要依赖老年代进行分配担保通过分配担保机制将存活的对象放入老年代即可 优点 实现简单运行高效复制之后保证空间的连续性不会出现“内存碎片” 缺点 存在空间浪费 应用场景 在新生代常规的垃圾回收一次可以回收大部分内存空间剩余存活对象不多因此现在的商业虚拟机都是用这种收集算法回收新生代 标记-压缩算法标记过程仍然与“标记-清除”算法一样之后将所有的存活对象压到内存的一端按顺序排放之后清理边界外的内存 优点 解决了标记-清除算法出现内存碎片的问题解决了复制算法中空间浪费的问题 缺点 效率上低于复制算法移动对象时如果对象被其他对象引用则还需要调整引用的地址移动过程中需要暂停用户应用程序。即 STW 分代收集算法把 Java 堆分为新生代和老年代这样就可以对不同生命周期的对象采取不同的收集方式以提高回收效率 当前商业虚拟机都采用这种算法 新生代中的对象生命周期短存活率低因此适合使用复制算法存活对象越少复制算法效率越高老年代中对象生命周期长存活率高回收没有新生代频繁一般使用标记-清除或者是标记-压缩