Java中的垃圾收集是Java程序执行自动内存管理的过程。Java程序编译成字节码,可以在Java虚拟机(简称JVM)上运行。当Java程序在JVM上运行时,会在堆上创建对象,堆是程序专用内存的一部分。最终,一些对象将不再需要。垃圾收集器会找到这些未使用的对象并删除它们以释放内存。
什么是垃圾收集?
在C/C++中,程序员负责创建和销毁对象。通常,程序员忽略了对无用对象的破坏。由于这种疏忽,在某一点上,可能没有足够的内存来创建新对象,整个程序将异常终止,导致 OutOfMemory错误 .
但是在Java中,程序员不需要关心所有不再使用的对象。垃圾收集器销毁这些对象。垃圾收集器的主要目标是通过销毁堆来释放堆内存 遥不可及的物体 垃圾回收器就是最好的例子 守护进程线程 因为它总是在后台运行。
Java中的垃圾收集是如何工作的?
Java垃圾收集是一个自动过程。自动垃圾收集是查看堆内存的过程,识别哪些对象正在使用,哪些未使用,并删除未使用的对象。正在使用的对象或引用的对象意味着程序的某些部分仍然保持指向该对象的指针。程序的任何部分都不再引用未使用或未引用的对象。因此,可以回收未引用对象使用的内存。程序员不需要显式地标记要删除的对象。垃圾收集实现存在于JVM中。
Java垃圾收集中的活动类型
Java中通常会发生两种类型的垃圾收集活动。这些是:
- 少量或增量垃圾收集: 据说,当年轻一代堆内存中无法访问的对象被删除时,就会发生这种情况。
- 主要或全部垃圾收集: 据说,在小规模垃圾收集中幸存下来的对象被复制到旧一代或永久一代堆内存中时,就会发生这种情况。与年轻一代相比,老一代收集垃圾的频率较低。
Java中与垃圾收集相关的重要概念
1.无法到达的对象: 如果一个对象不包含对它的任何引用,则称其为不可访问。此外,请注意,作为隔离岛一部分的对象也是无法到达的。
Integer i = new Integer(4);// the new Integer object is reachable via the reference in 'i' i = null;// the Integer object is no longer reachable.
2.垃圾收集资格: 如果对象不可访问,则称其符合GC(垃圾收集)的条件。之后 i=零 ,堆区域中的整数对象4适用于上图中的垃圾收集。
使对象符合垃圾收集器条件的方法
- 尽管程序员不负责销毁无用的对象,但如果不再需要,强烈建议使对象不可访问(因此符合GC条件)。
- 通常有四种方法可以使对象符合垃圾收集的条件。
- 使引用变量为空
- 重新分配参考变量
- 在方法内部创建的对象
- 孤岛
请求的方式 JVM 运行垃圾收集器
- 一旦我们使一个对象符合垃圾收集的条件,垃圾收集器可能不会立即销毁它。每当JVM运行垃圾收集器程序时,只有对象会被销毁。但是当JVM运行垃圾收集器时,我们不能期望。
- 我们还可以请求JVM运行垃圾收集器。有两种方法:
- 使用 系统gc() 方法: 系统类包含静态方法 gc() 用于请求JVM运行垃圾收集器。
- 使用 运行时。getRuntime()。gc() 方法: 运行时类 允许应用程序与运行应用程序的JVM接口。因此,通过使用它的gc()方法,我们可以请求JVM运行垃圾收集器。
- 不能保证上述两种方法中的任何一种都会运行垃圾收集器。
- 电话 系统gc() 实际上相当于通话: 运行时。getRuntime()。gc()
定稿
- 就在销毁对象之前,垃圾收集器调用 定稿 方法来执行清理活动。一旦 定稿 方法完成时,垃圾收集器将销毁该对象。
- 定稿 方法出现在 对象类 使用以下原型。
protected void finalize() throws Throwable
根据我们的要求,我们可以 定稿 方法来执行清理活动,例如关闭数据库的连接。
- 这个 定稿 方法由垃圾收集器而不是JVM调用。然而,垃圾收集器是JVM的模块之一。
- 对象类 定稿 方法的实现为空。因此,建议覆盖 定稿 方法来处理系统资源或执行其他清理。
- 这个 定稿 方法对于任何对象都不会被多次调用。
- 如果 定稿 方法,则忽略该异常,并终止该对象的终结。
Java中垃圾收集的优势
Java中垃圾收集的优点是:
- 它使java内存更高效,因为垃圾收集器从堆内存中删除未引用的对象。
- 它是由垃圾收集器(JVM的一部分)自动完成的,因此我们不需要额外的工作。
现实世界的例子
让我们举一个现实生活中的例子,我们使用垃圾收集器的概念。
问题: 假设你去Geeksforgeks实习,你被告知要写一个程序来统计在公司工作的员工人数(不包括实习生)。要制作这个程序,必须使用垃圾收集器的概念。
这是公司给你的实际任务:
编写一个程序来创建一个名为Employee的类,该类包含以下数据成员。
1.用于存储分配给每位员工的唯一ID的ID。 2.员工姓名。 3.员工的年龄。
此外,请提供以下方法:
- 用于初始化名称和年龄的参数化构造函数。应该在此构造函数中初始化ID。
- 显示ID、姓名和年龄的方法show()。
- 方法showNextId()显示下一个员工的ID。
现在,任何不了解Java中垃圾收集器的初学者都会编写如下代码:
JAVA
// Java Program to count number // of employees working // in a company class Employee { private int ID; private String name; private int age; private static int nextId = 1 ; // it is made static because it // is keep common among all and // shared by all objects public Employee(String name, int age) { this .name = name; this .age = age; this .ID = nextId++; } public void show() { System.out.println( "Id=" + ID + "Name=" + name + "Age=" + age); } public void showNextId() { System.out.println( "Next employee id will be=" + nextId); } } class UseEmployee { public static void main(String[] args) { Employee E = new Employee( "GFG1" , 56 ); Employee F = new Employee( "GFG2" , 45 ); Employee G = new Employee( "GFG3" , 25 ); E.show(); F.show(); G.show(); E.showNextId(); F.showNextId(); G.showNextId(); { // It is sub block to keep // all those interns. Employee X = new Employee( "GFG4" , 23 ); Employee Y = new Employee( "GFG5" , 21 ); X.show(); Y.show(); X.showNextId(); Y.showNextId(); } // After countering this brace, X and Y // will be removed.Therefore, // now it should show nextId as 4. // Output of this line E.showNextId(); // should be 4 but it will give 6 as output. } } |
Id=1Name=GFG1Age=56Id=2Name=GFG2Age=45Id=3Name=GFG3Age=25Next employee id will be=4Next employee id will be=4Next employee id will be=4Id=4Name=GFG4Age=23Id=5Name=GFG5Age=21Next employee id will be=6Next employee id will be=6Next employee id will be=6
现在要获得正确的输出: 现在垃圾收集器(gc)将看到两个对象空闲。现在,为了减少nextId,只有当我们的程序员在类中重写了finalize()方法时,gc(垃圾收集器)才会调用finalize()方法。如前所述,我们必须请求gc(垃圾收集器),为此,我们必须在关闭子块的大括号之前编写以下3个步骤。
- 将引用设置为null(即X=Y=null;)
- 呼叫,系统。gc();
- 呼叫,系统。runFinalization();
现在是计算员工人数(不包括实习生)的正确代码
JAVA
// Correct code to count number // of employees excluding interns. class Employee { private int ID; private String name; private int age; private static int nextId = 1 ; // it is made static because it // is keep common among all and // shared by all objects public Employee(String name, int age) { this .name = name; this .age = age; this .ID = nextId++; } public void show() { System.out.println( "Id=" + ID + "Name=" + name + "Age=" + age); } public void showNextId() { System.out.println( "Next employee id will be=" + nextId); } protected void finalize() { --nextId; // In this case, // gc will call finalize() // for 2 times for 2 objects. } } public class UseEmployee { public static void main(String[] args) { Employee E = new Employee( "GFG1" , 56 ); Employee F = new Employee( "GFG2" , 45 ); Employee G = new Employee( "GFG3" , 25 ); E.show(); F.show(); G.show(); E.showNextId(); F.showNextId(); G.showNextId(); { // It is sub block to keep // all those interns. Employee X = new Employee( "GFG4" , 23 ); Employee Y = new Employee( "GFG5" , 21 ); X.show(); Y.show(); X.showNextId(); Y.showNextId(); X = Y = null ; System.gc(); System.runFinalization(); } E.showNextId(); } } |
输出
Id=1Name=GFG1Age=56Id=2Name=GFG2Age=45Id=3Name=GFG3Age=25Next employee id will be=4Next employee id will be=4Next employee id will be=4Id=4Name=GFG4Age=23Id=5Name=GFG5Age=21Next employee id will be=6Next employee id will be=6Next employee id will be=4
相关文章:
本文由 Chirag Agarwal和Gaurav Miglani 。如果您发现任何不正确的地方,或者您想分享有关上述主题的更多信息,请写下评论。