赞
踩
Java垃圾回收机制是Java虚拟机(JVM)的核心组件之一,对于内存管理起到至关重要的作用。它能自动追踪并管理应用程序中创建的对象,当这些对象不再使用时,垃圾回收机制会自动回收其占用的内存,使这部分内存能够被再次利用。此机制极大地减少了开发者需要手动管理内存的负担,防止了因为疏忽导致的内存泄漏问题,是Java语言相较于C++等其他语言的一个显著优点。
Java内存主要被划分为五个区域:
其中,方法区和堆是Java垃圾收集器关注的主要区域,也是我们接下来讨论的重点。
在Java中,对象的生命周期从创建(new)开始,到不再被其他对象引用结束。换句话说,当一个对象没有任何引用指向它时,这个对象就成了垃圾,等待垃圾回收器的回收。值得注意的是,对象可能还在作用域中,但已经不可能被程序再次使用(如:对象只在一个局部作用域中使用),此时这个对象也会被视为垃圾。垃圾回收器的主要工作就是找出这些垃圾对象并释放它们占用的内存,从而为新的对象提供空间。
这是最基础的垃圾收集算法。它分为两个阶段:标记阶段和清除阶段。标记阶段会遍历所有的对象,找出还活着的对象。清除阶段则会清除掉所有未被标记的对象。如图:
虽然标记-清除算法很直观,但存在两个问题:一是效率问题,标记和清除两个过程的效率都不高;二是空间问题,标记清除之后会产生大量不连续的内存碎片。
为了解决效率问题,可以采用"复制"算法。复制算法将可用内存按容量划分为大小相等的两块,每次只使用其中一块。当这一块内存用完了,就将还活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次性清理掉。这样使得每次都是对其中一块进行内存回收,内存分配时也就不用考虑内存碎片等问题。如图:
复制算法虽然实现简单,内存效率高,不易产生碎片,但是最大的问题是可用内存被压缩到了原本的一半,未充分利用内存。且存活对象增多的话,复制算法的效率会大大降低。
为了解决空间问题,可以使用"标记-整理"算法。标记过程仍然与"标记-清除"算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。如图:
当前商业虚拟机的垃圾收集都采用"分代收集"(Generational Collection)算法。这种算法把Java堆分为新生代和老年代,这样我们就可以根据各个年代的特点采用最适当的收集算法。在对象存活率低的新生代,可以选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。而老年代中因为对象存活率高、没有额外空间对它进行分配担保,我们可以选择"标记-清理"或者"标记-整理"算法进行垃圾收集。
注意,Java本身并不提供直接控制这些垃圾收集算法的API,它们是由Java虚拟机在后台自动执行的。然而,理解这些基础的垃圾收集算法是理解更高级的垃圾收集技术(如:并行收集、并发收集、增量收集等)的基础。
Java HotSpot VM包含几种类型的垃圾收集器,每一种都有各自的特点,适用于不同的系统和使用场景。包括:
需要注意的是,每种垃圾收集器都有其适用的场景,没有绝对的好坏之分。在实际的系统设计和开发中,我们需要根据应用的特性(如:是否对系统响应时间有较高要求等)和硬件资源来选择最合适的收集器。
在Java中,垃圾回收的触发时机是由JVM来决定的。虽然我们可以通过调用System.gc()
方法来请求JVM进行垃圾回收,但这只是一个建议,JVM可以选择忽略这个请求。
在实际情况中,JVM通常会在以下几种情况下进行垃圾回收:
下面的Java代码将显示在运行过程中垃圾回收的执行情况:
public class GCDemo {
public static void main(String[] args) {
Runtime runtime = Runtime.getRuntime();
long before = runtime.freeMemory(); //获取开始时JVM空闲内存
for (int i = 0; i < 1000000; i++) {
String s = new String("Hello, World!");
s = null; // 显式地断开s的引用,使得s所指向的对象可以被垃圾回收
}
long after = runtime.freeMemory(); //获取结束时JVM空闲内存
System.out.println("Memory freed by GC: " + (before - after));
}
}
这段代码会输出由垃圾回收器释放的内存量,可以看到,即使我们没有显式地触发垃圾回收,JVM也会在适当的时机进行垃圾回收。
理解和掌握Java的垃圾回收机制对于编写高效、稳定的Java程序至关重要。在这篇博客中,我们介绍了垃圾回收机制的基本原理,JVM的内存结构,垃圾回收算法,各种垃圾收集器,以及垃圾回收的触发时机。虽然Java已经为我们处理了大部分的内存管理问题,但是,作为Java开发人员,我们仍然需要理解这些基本的概念,才能写出更有效率的代码,并避免出现内存泄漏等问题。希望这篇博客对你有所帮助,如果你有任何问题,欢迎留言讨论。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。