京东购物网站怎么做,资源下载网站源码,浙江省住房和城乡建设厅网站 文件,工信部网站 登陆文章目录 垃圾回收机制垃圾判断算法引用计数法可达性分析算法虚拟机栈中的引用#xff08;方法的参数、局部变量等#xff09;本地方法栈中 JNI 的引用类静态变量运行时常量池中的常量 垃圾收集算法Mark-Sweep#xff08;标记-清除#xff09;算法Copying#xff08;标记-… 文章目录 垃圾回收机制垃圾判断算法引用计数法可达性分析算法虚拟机栈中的引用方法的参数、局部变量等本地方法栈中 JNI 的引用类静态变量运行时常量池中的常量 垃圾收集算法Mark-Sweep标记-清除算法Copying标记-复制算法Mark-and-Compact标记-整理算法Generation Collection (分代收集) 算法 垃圾回收机制
垃圾回收Garbage CollectionGC顾名思义就是释放垃圾占用的空间当需要排查各种内存溢出问题、当垃圾收集成为系统达到更高并发的瓶颈时我们就需要对这些“自动化”的技术实施必要的监控和调节。有效的使用可以使用的内存对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收。
垃圾判断算法
引用计数法
给对象中添加一个引用计数器
每当有一个地方引用它计数器就加 1当引用失效计数器就减 1任何时候计数器为 0 的对象就是不可能再被使用的。
这个方法实现简单效率高但是目前主流的虚拟机中并没有选择这个算法来管理内存其最主要的原因是它很难解决对象之间循环引用的问题。 可达性分析算法
该算法通过一系列的称为 “GC Roots” 的对象作为起点从这些节点开始向下搜索节点所走过的路径称为引用链当一个对象到 GC Roots 没有任何引用链相连的话则证明此对象是不可用的需要被回收。 图片来源JavaGuide Object 6 ~ Object 10 之间虽有引用关系但它们到 GC Roots 不可达因此为需要被回收的对象
所谓对象之间的相互引用问题除了对象 objA 和 objB 相互引用着对方之外这两个对象之间再无任何引用。但是他们因为互相引用对方导致它们的引用计数器都不为 0于是引用计数算法无法通知 GC 回收器回收他们。
所谓的 GC Roots就是一组必须活跃的引用不是对象它们是程序运行时的起点是一切引用链的源头。在 Java 中GC Roots 包括以下几种
虚拟机栈中的引用方法的参数、局部变量等本地方法栈中 JNI 的引用类静态变量运行时常量池中的常量String 或 Class 类型
虚拟机栈中的引用方法的参数、局部变量等
public class StackReference {public void greet() {Object localVar new Object(); // 这里的 localVar 是一个局部变量存在于虚拟机栈中System.out.println(localVar.toString());}public static void main(String[] args) {new StackReference().greet();}
}在 greet 方法中localVar 是一个局部变量存在于虚拟机栈中可以被认为是 GC Roots。
在 greet 方法执行期间localVar 引用的对象是活跃的因为它是从 GC Roots 可达的。
当 greet 方法执行完毕后localVar 的作用域结束localVar 引用的 Object 对象不再由任何 GC Roots 引用假设没有其他引用指向这个对象因此它将有资格作为垃圾被回收掉。
本地方法栈中 JNI 的引用
Java 通过 JNIJava Native Interface提供了一种机制允许 Java 代码调用本地代码通常是 C 或 C 编写的代码。
当调用 Java 方法时虚拟机会创建一个栈帧并压入虚拟机栈而当它调用本地方法时虚拟机会通过动态链接直接调用指定的本地方法。 JNI 引用是在 Java 本地接口JNI代码中创建的引用这些引用可以指向 Java 堆中的对象。
// 假设的JNI方法
public native void nativeMethod();// 假设在C/C中实现的本地方法
/** Class: NativeExample* Method: nativeMethod* Signature: ()V*/
JNIEXPORT void JNICALL Java_NativeExample_nativeMethod(JNIEnv *env, jobject thisObj) {jobject localRef (*env)-NewObject(env, ...); // 在本地方法栈中创建JNI引用// localRef 引用的Java对象在本地方法执行期间是活跃的
}在本地C/C代码中localRef 是对 Java 对象的一个 JNI 引用它在本地方法执行期间保持 Java 对象活跃可以被认为是 GC Roots。
一旦 JNI 方法执行完毕除非这个引用是全局的Global Reference否则它指向的对象将会被作为垃圾回收掉假设没有其他地方再引用这个对象。
类静态变量
来看下面这段代码
public class StaticFieldReference {private static Object staticVar new Object(); // 类静态变量public static void main(String[] args) {System.out.println(staticVar.toString());}
}StaticFieldReference 类中的 staticVar 引用了一个 Object 对象这个引用存储在元空间可以被认为是 GC Roots。
只要 StaticFieldReference 类未被卸载staticVar 引用的对象都不会被垃圾回收。如果 StaticFieldReference 类被卸载这通常发生在其类加载器被垃圾回收时那么 staticVar 引用的对象也将有资格被垃圾回收如果没有其他引用指向这个对象。
运行时常量池中的常量
public class ConstantPoolReference {public static final String CONSTANT_STRING Hello, World; // 常量存在于运行时常量池中public static final Class? CONSTANT_CLASS Object.class; // 类类型常量public static void main(String[] args) {System.out.println(CONSTANT_STRING);System.out.println(CONSTANT_CLASS.getName());}
}在 ConstantPoolReference 中CONSTANT_STRING 和 CONSTANT_CLASS 作为常量存储在运行时常量池。它们可以用来作为 GC Roots。
这些常量引用的对象字符串Hello, World和 Object.class 类对象在常量池中只要包含这些常量的 ConstantPoolReference 类未被卸载这些对象就不会被垃圾回收。
垃圾收集算法
垃圾收集算法Garbage Collection Algorithm) 是一种自动内存管理机制用于在程序运行时自动识别和回收不再使用的对象以释放内存空间和提升系统性能
Mark-Sweep标记-清除算法 图片来源JavaGuide 标记-清除Mark-and-Sweep算法分为“标记Mark”和“清除Sweep”阶段首先标记出所有不需要回收的对象在标记完成后统一回收掉所有没有被标记的对象。
它是最基础的收集算法后续的算法都是对其不足进行改进得到。这种垃圾收集算法会带来两个明显的问题
效率问题标记和清除两个过程效率都不高。空间问题标记清除后会产生大量不连续的内存碎片。
对于标记的对象是可回收还是不可回收对象两种说法都有支持者按照前者
当一个对象被创建时给一个标记位假设为 0 (false)在标记阶段从根对象出发将所有可达对象或用户可以引用的对象的标记位设置为 1 (true)扫描阶段 清除标记位为 0 (false)的对象。
Copying标记-复制算法 图片来源JavaGuide 为了解决 标记-清除 算法的效率和内存碎片问题复制Copying收集算法 将内存分为大小相同的两块每次使用其中的一块。
当这一块的内存使用完后就将还存活的对象复制到另一块去然后再把使用的空间一次清理掉。这样就使每次的内存回收都是对内存区间的一半进行回收。
该算法存在的问题
可用内存变小可用内存缩小为原来的一半。不适合老年代如果存活对象数量比较大复制性能会变得很差。
Mark-and-Compact标记-整理算法 图片来源JavaGuide 标记-整理Mark-and-Compact算法是根据老年代的特点提出的一种标记算法标记过程仍然与“标记-清除”算法一样但后续步骤是让所有存活的对象向一端移动然后直接清理掉端边界以外的内存。
由于多了整理这一步因此效率不高适合老年代这种垃圾回收频率不是很高的场景。
Generation Collection (分代收集) 算法
当前虚拟机的垃圾收集都采用分代收集算法这种算法没有什么新的思想只是根据对象存活周期的不同将内存分为几块。一般将 Java 堆分为新生代和老年代根据各个年代的特点选择合适的垃圾收集算法通过优化垃圾收集的效率提高了系统的性能。
比如在新生代中每次 GC 都会有大量对象死去可以选择 Copying 算法只需要付出少量对象的复制成本就可以完成每次垃圾收集。
而老年代的对象存活几率是比较高的而且没有额外的空间对它进行分配担保必须选择“标记-清除”或“标记-整理”算法进行垃圾收集。
Java 虚拟机JVM中的垃圾收集器通常会根据堆内存的大小、对象的存活时间等因素动态选择合适的垃圾收集算法和策略以最大程度地提高内存利用率和应用程序的性能。