大家都知道使用new运算符在内存中创建了一个对象。构造函数用于初始化该对象的属性。当不再需要某个对象时,必须将其从内存中删除,以便该内存可以重用于其他对象。从内存中删除不需要的对象或放弃的对象称为垃圾回收(GC)。在像C ++这样的语言中,GC是使用析构函数手动执行的。

但是,java中没有析构函数。在java中,存在更好的处理垃圾收集的机制。您无需显式删除不需要的对象。JVM为您完成此任务。JVM隐式地从内存中清除被遗弃的对象。

在继续java中的垃圾收集之前,让我们看一下Object类的finalize()方法。

Java中的finalize方法

finalize()方法是java.lang.Object类的受保护和非静态方法。你可以在java中创建的所有对象中使用此方法。此方法用于在对象从内存中删除之前对对象执行某些最终操作或清理操作。您可以覆盖finalize()方法,以便在销毁对象之前保留要执行的操作。这是finalize()方法的一般形式。

protected void finalize() throws Throwable
{
//Keep some resource closing operations here
}

Java中的垃圾收集

无论何时运行java程序,JVM都会创建三个线程。1)主线程;2)线程调度器;3)垃圾收集器线程。在这三个线程中,主线程是用户线程,剩下的两个是在后台运行的守护线程。

主线程的任务是执行main()方法。线程调度程序的任务是调度线程。垃圾收集器线程的任务是从堆内存中清除废弃的对象。被遗弃的对象或死对象是那些没有实时引用的对象。垃圾收集器线程在扫除一个废弃的对象之前,它调用该对象的finalize()方法。执行finalize()方法后,对象将从内存中销毁。这意味着在从内存中销毁对象之前,执行在finalize()方法中保留的清理操作。

只要对象被放弃,垃圾收集器线程就不会进入堆内存。它偶尔出现在堆内存中,当时如果它看到任何被遗弃的对象,它会在调用finalize()方法之后扫除这些对象。垃圾收集器线程仅对一个对象调用finalize()方法一次。

让我们讨论一些关于垃圾收集和finalize()方法的有趣观点。

关于垃圾收集的一些有趣点和Java中的finalize()方法

1)在某些情况下,垃圾收集器线程根本不调用finalize()方法。例如,当我在系统中执行以下程序时,A类的finalize()方法根本没有执行。

class A
{
int i = 50;
@Override
protected void finalize() throws Throwable
{
System.out.println("From Finalize Method");
}
}
public class Test
{
public static void main(String[] args)
{
//Creating two instances of class A
A a1 = new A();
A a2 = new A();
//Assigning a2 to a1
a1 = a2;
//Now both a1 and a2 will be pointing to same object
//An object earlier referred by a1 will become abandoned
System.out.println("done");
}
}

2)可以使用 Runtime.getRuntime().runFinalization() 或 Runtime.runFinalizersOnExit(true)强制执行finalize()方法。但是,这两种方法都有缺点。Runtime.getRuntime().runFinalization() 尽最大努力执行finalize()方法,但不保证finalize()方法一定被执行。在JDK中不推荐使用Runtime.runFinalizersOnExit(true) ,因为有时它也会在仍然活跃的对象上运行finalize()方法。

class A
{
int i = 50;
@Override
protected void finalize() throws Throwable
{
System.out.println("From Finalize Method");
}
}
public class Test
{
public static void main(String[] args)
{
//Creating two instances of class A
A a1 = new A();
A a2 = new A();
//Assigning a2 to a1
a1 = a2;
//Making finalize() method to execute forcefully
Runtime.getRuntime().runFinalization();
System.out.println("done");
}
}

3)可以使用 System.gc()或RunTime.getRunTime().gc()进行显式地调用垃圾收集。同样,它只是对垃圾收集器的请求而不是命令,垃圾收集器可以满足此要求。

class A
{
int i;
public A(int i)
{
this.i = i;
}
@Override
protected void finalize() throws Throwable
{
System.out.println("From Finalize Method, i = "+i);
}
}
public class Test
{
public static void main(String[] args)
{
//Creating two instances of class A
A a1 = new A(10);
A a2 = new A(20);
//Assigning a2 to a1
a1 = a2;
//Now both a1 and a2 will be pointing same object
//An object earlier referred by a1 will become abandoned
//Calling garbage collector thread explicitly
System.gc(); //OR call Runtime.getRuntime().gc();
System.out.println("done");
}
}

4) finalize()方法不像构造函数那样是链式调用。对于子类的finalize()方法内部的超类finalize()方法没有调用语句。您需要显式调用超类finalize()方法。

protected void finalize() throws Throwable
{
System.out.println("From Finalize Method");
//Calling super class finalize() method explicitly
super.finalize();
}

5) finalize()方法中发生的异常不会传播。它们会被垃圾收集器忽略。

6)在丢弃对象之前,可以在对象上显式调用finalize()方法。调用时,只对对象执行finalize()方法中保持对象操作,对象不会从内存中销毁。

class A
{
int i;
public A(int i)
{
this.i = i;
}
@Override
protected void finalize() throws Throwable
{
System.out.println("From Finalize Method, i = "+i);
//Calling super class finalize() method explicitly
super.finalize();
}
}
public class Test
{
public static void main(String[] args)
{
//Creating two instances of class A
A a1 = new A(10);
A a2 = new A(20);
//Calling finalize() method of a1 before it is abandoned
try
{
a1.finalize();
}
catch (Throwable e)
{
e.printStackTrace();
}
//Assigning a2 to a1
a1 = a2;
//Now both a1 and a2 will be pointing same object
//An object earlier referred by a1 will become abandoned
System.out.println("done");
}
}

7)丢弃对象的finalize()方法仅由垃圾收集器线程调用一次。GC忽略开发人员在对象上调用的finalize()方法。

参考引用