由运行的 Java 应用程序创建的所有对象都存储在 Java 虚拟机的堆内存中. 一旦创建了对象, 它们永远不会被代码本身释放, 因为 Java 具有垃圾收集过程, 该过程是自动释放程序不再引用或使用的对象的过程.
小编这里有一份 Java 学习资料, 加我的个人 QQ:2397938575, 就能免费领取这份资料, 我会私发给你, 长期真实有效! 以下为部分 Java 基础资料截图!
"垃圾回收" 这个名字用于 java 应用程序不再需要的对象, 或者程序是 "垃圾" 的, 可以被扔掉. Java 中的垃圾收集也被称为或更为准确和最新的垃圾收集比喻是 "内存回收". 它基本上用于回收由 java 程序不再引用的对象所占用的堆空间, 并且可以将其用于随后的新对象. 垃圾收集器的责任是以某种方式确定程序中不再需要或引用哪些对象, 并将其从堆空间中移除. 在这个过程中, 垃圾回收器必须运行 finalize 方法, 以便将来需要或可以引用的对象获得生存的机会.
JVM 体系结构
下面的图表总结了一个带有关键组件的 JVM 体系结构. 堆栈内存和垃圾收集器在这个图表中或在与垃圾收集相关的 JVM 体系结构中有两个主要组件.
垃圾收集根 - 所有对象树的来源
每个对象树中都有一个或多个根对象. 如果我们能够到达树中的这些根, 那么它适用于整个对象树是可到达的并且不能被垃圾收集. 我们应该能够知道这些根对象何时被认为可以访问? 称为垃圾收集根的特殊对象始终可以访问, 任何在其根目录中都有垃圾收集根的对象也是如此. Java 中有四种 GC 根源
i. 一个线程的堆栈保持 Java 应用程序或程序中的局部变量. 这实际上并不可见, 因为这不是真正的对象的虚拟参考. 所以这就是为什么对于所有的意图和目的, 局部变量是垃圾收集的根源.
i. 在 Java 应用程序中处于活动状态的 Java 线程始终被视为活动对象, 因此被视为 GC 根. 这对线程局部变量尤其重要.
i. 也称为类变量的静态变量是通过类中的 static 关键字声明的. 这个事实本身就是 GC 的根源. 类可以被垃圾收集, 这将删除所有引用的静态变量. 一般来说, 当我们使用应用程序服务器或类加载器时, 这是特别重要的.
i. 本地代码创建 JNI(被称为 java 对象) 引用作为 JNI 调用的一部分. 由这种本地代码创建的对象会被特别对待, 因为 JVM 不知道它们是否被本机代码引用. 这样的 Java 对象代表了一种非常特殊的 GC 形式.
垃圾收集算法: 标记和清除垃圾
垃圾收集使用标记和扫描算法来确定哪些对象不再被使用. JVM 间歇地运行这个算法. 在垃圾收集算法中, 我们必须执行两个基本的事情 (标记和扫描).
. 该算法遍历所有对象引用, 从 GC 根开始, 并标记每个找到的对象. 它必须检测首先标记的对象, 这些对象不再被程序引用, 并且可以被垃圾收集.
. 没有被标记的对象占用的所有堆内存都被回收. 它被简单地标记为空闲的, 基本上没有未使用的对象. 它应该通过清除标记的 对象来回收这些对象所使用的空间, 并将该空间再次提供给程序, 以便使用这个堆空间来创建新的对象.
垃圾收集在内存管理中非常有用, 因为它允许开发者创建新的对象而不用担心内存分配和释放. 因为垃圾收集器为开发人员这样做, 即它会自动回收内存以供重用. 这有助于更快的开发, 也有助于消除内存泄漏和其他内存相关的问题. 垃圾收集旨在消除经典内存泄漏的原因: 内存中无法访问但未被删除的对象.
但是, 这只适用于原始意义上的内存泄漏. 我们想要被垃圾收集的对象需要被开发者解除引用, 这样垃圾收集才能标记它. 开发人员可能会忘记解除引用, 因此可能会有一些应用程序仍然可以访问的未使用的对象. 这些物体不能被垃圾收集. 更糟的是任何软件都无法检测到这种逻辑内存泄漏. 当对象不再被 GC 根直接或间接引用时, 它们将被删除. 没有经典的内存泄漏. 分析不能真正识别内存泄漏, 只能指出可疑对象.
我们也可以通过调用 System.gc() 命令来手动调用垃圾收集. 但是不能保证立即调用垃圾收集. 在渗透之前, GC 调用 finalize 方法, 以便仍然需要的对象有机会保存自己. finalize 方法 GC 直接调用 sweep step 之后, 删除不再需要的对象.
来源: http://www.jianshu.com/p/aad74df5dc4a