如何在Java中销毁对象?

55

我在一次面试中遇到了这个问题,选项如下:

如何在Java中销毁一个对象?

a. System.gc();  
b. Runtime.getRuntime.gc();  
c. object.delete();  
d. object.finalize();  
e. Java performs gc by itself, no need to do it manually.
  1. 答案应该是e吗?

  2. 如果e不存在会怎样?那么? 显然c不是答案。a和b将为整个应用程序进行垃圾收集(问题要求一个对象)。我认为是d,因为finalize()在gc之前被调用(但是在finalize之后是否必须调用gc呢?)或者我错了?必须有e才能回答这个问题吗?


8
如果没有"e",你需要自己写出来。其他选项都不是答案。 - Luiggi Mendoza
2
Java不允许你销毁对象。任何无法访问的对象可能(或可能不会)在任何特定时间被垃圾回收。 - Mechanical snail
6个回答

64

答案是选项 E。如果没有选项 E,你很快就会耗尽内存(或者)没有正确的答案。

对象必须是不可达的才能有资格进行垃圾回收。JVM 将进行多次扫描,将对象从一个代移动到另一个代以确定垃圾回收的资格,并在对象不可达时释放内存。


1
这是正确的。没有正确答案,但是选择 E 是正确的。否则 Java 将变成 C++。 - Sid
8
即使对象“不可达”,它们仍然可以在整个应用程序的生命周期内存在,这并不完全正确,这与它们被删除没有太大关系,更多地与内存压力有关。JVM不会尝试维护最大空闲空间,因为那样会浪费资源。 - user177800

41
为了澄清为什么其他答案行不通:
  1. System.gc()(连同 Runtime.getRuntime().gc(),它们的作用是相同的)暗示你想要销毁东西。模糊的。JVM可以忽略运行GC周期的请求,如果它认为没有必要的话。另外,除非您已将所有可达引用对象的引用设置为空,否则GC也无法触及该对象。 因此,A和B都被淘汰。

  2. Runtime.getRuntime.gc()语法错误。 getRuntime是一个函数,而不是变量。需要在它后面加括号来调用它。所以B被双淘汰了。

  3. Object没有delete方法。因此C被淘汰了。

  4. 虽然Object确实有一个finalize方法,但它并不会销毁任何东西。只有垃圾收集器才能真正删除对象。 (在许多情况下,他们甚至不会费心去做那个;他们只是不复制它,因此它被留下。)所有finalize做的就是在JVM丢弃它之前给对象一个清理的机会。此外,您永远不应直接调用finalize。(由于finalize是protected,因此JVM也不会让您在任意对象上调用它。)所以D被淘汰了。

  5. 除此之外,object.doAnythingAtAllEvenCommitSuicide()要求运行代码拥有对object的引用。这就使它变得“活着”,从而无法进行垃圾回收。因此,C和D被双淘汰了。


4
应该有一种编程语言,其中像这样的宝石应该是合法的语句 -> object.doAnythingAtAllEvenCommitSuicide() - tired and bored dev

18

简短回答 - E

答案是E,因为其他选项都显然是错误的,但是...

长回答 - 情况并不那么简单;它取决于...

事实是,垃圾收集器可能永远不会决定对每个可回收对象进行垃圾收集,除非内存压力极高。而且,Java与任何其他语言一样容易出现内存泄漏,只是更难引起,因此在引起它们时更难找到!

以下文章详细介绍了内存管理的工作原理和不起作用的内容以及什么被占用。 生成式垃圾收集器的工作原理感谢内存(了解JVM如何在Windows和Linux上使用本机内存)

如果你阅读这些链接,我认为你会明白在Java中的内存管理并不像选择题那么简单。


14

将其设置为null。这样就没有引用了,对象就变得适合进行垃圾回收。GC会自动从堆中删除对象。


你真是个天才!即使该类有一个finalize方法,这种方法在我的情况下也不起作用。通过这样做,它立即被垃圾回收并修复了绘图问题。谢谢。 - LFMekz

5

以下是代码:

public static void main(String argso[]) {
int big_array[] = new int[100000];

// Do some computations with big_array and get a result. 
int result = compute(big_array);

// We no longer need big_array. It will get garbage collected when there
// are no more references to it. Since big_array is a local variable,
// it refers to the array until this method returns. But this method
// doesn't return. So we've got to explicitly get rid of the reference
// ourselves, so the garbage collector knows it can reclaim the array. 
big_array = null;

// Loop forever, handling the user's input
for(;;) handle_input(result);
}

0
在Java中,没有显式的垃圾回收方式。JVM本身运行一些后台线程,检查那些没有任何引用的对象,这意味着我们访问对象的所有方式都已丢失。另一方面,如果对象超出范围,也就是创建对象的程序终止或结束,则该对象也符合垃圾回收的条件。
回到您的问题,方法finalize与C++中的析构函数相同。在JVM清除对象内存之前,实际上会调用finalize方法。在程序中定义finalize方法与否由您决定。但是,如果对象的垃圾回收是在程序终止后完成的,则JVM不会调用您在程序中定义的finalize方法。
您可能会问finalize方法有什么用处?例如,假设您创建了一个需要某些流到外部文件的对象,并明确为此对象定义了finalize方法,该方法检查流是否打开到文件,如果没有,则关闭流。假设在编写几行代码后,您丢失了对该对象的引用。然后它就符合垃圾回收的条件。当JVM即将释放对象空间时,JVM只需检查您是否定义了finalize方法并调用该方法,因此打开的流没有风险。finalize方法使程序无风险且更加健壮。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接