当前位置: 首页 > 面试题库 >

当我们显式调用finalize()时,是否释放了对象内存?

颛孙智勇
2023-03-14
问题内容

就我的理解而言,finalize()和GC是两个不同的方面。GC使用finalize()方法释放对象内存。我们无法声明何时发生GC(即使我们显式调用System.gc())。但是我们可以在对象上显式调用finalize()。

Will the function be executed immediately(memory freed) or it waits till GC
occurs like System.gc() call?

同样,按照docs,对于任何给定对象,Java虚拟机都不会多次调用finalize方法。

因此,当我们先调用finalize()且GC在以后的时间点发生时,会发生什么。

If object memory is not freed on explicit call to object.finalize() then would't 
it being called again in the GC process violate the calling only once rule?

问题答案:

你完全错了。

简短答案:这
finalize()是一种在对象准备好进行垃圾回收之前(当没有对象对其进行强烈引用时)清理资源(例如打开的文件)的方法。它可能/不被调用。这是内存释放之前的第一步。

长答案:

有一个单独的守护程序线程称为finalizer线程,它负责调用finalize()方法。终结队列是放置准备好要调用finalize()方法的对象的队列。

  1. 创建对象时,JVM将检查用户是否覆盖了finalize()方法。如果具有,则在内部指出该特定对象具有finalize()方法。

当对象准备好进行垃圾回收时,垃圾回收器线程会检查该特定对象是否具有(1)中提到的表中的finalize()。

  • 2a)如果没有,则将其发送以进行垃圾回收。

2b)有,然后将其添加到完成队列。并且它从表(1)中删除对象的条目。

终结器线程不断轮询队列。对于队列中的每个对象,将调用其finalize()方法。在调用finalize()循环之后,再次重复从(2)开始的循环。如果该对象仍然没有强引用,则发送给GC。如果具有,那么将始终调用(2a),因为该条目已在(2b)中删除

Basically finalize() method is only called once.

那么上述周期有什么问题?

从(1)。在对象创建上需要花费额外的时间。Java中的内存分配比malloc /
calloc等快5到10倍。在表等对象的记录过程中,所有获得的时间都浪费了。我曾经尝试过。在一个循环中创建100000个对象,并在2种情况下测量程序终止所需的时间:一种不带有finalize(),第二种不带有finalize()。发现它快了20%。

从(2b):内存泄漏和饥饿。如果队列中的对象引用了很多内存资源,那么除非这些对象准备好用于GC,否则所有这些对象都不会被释放;如果所有对象都是重量级对象,则可能会短缺。

从(2b):因为finalize()仅被调用一次,所以如果在finalize()中您强烈引用了“
this”对象。下次永不调用该对象的finalie(),因此可能使该对象处于不一致状态。

如果在finalize()内部抛出异常,则将其忽略。

您不知道何时调用finalize(),因为您无法控制何时调用GC。有时可能会在finalize()中打印值,但是却永远不会显示输出,因为您的程序可能在调用finalize()时就被终止了。

因此,请避免使用它。而是创建一个方法,例如dispose(),它将关闭必需的资源或用于最终日志等。



 类似资料:
  • wcsdup等函数隐式调用malloc为目标缓冲区分配内存。我想知道,由于内存分配不是很明确,所以显式释放存储似乎合乎逻辑吗?这更像是一种设计困境,赞成和反对的理由如下 应释放,因为 不释放它会导致内存泄漏。 wcsdup/_wcsdup调用malloc来分配内存,即使是从C程序调用的。 不应该被释放,因为 wcsdup积累的内存最终会在程序退出时被释放。在整个程序生命周期中,我们总是会遇到一些内

  • 我有下面的课。 我创建了一个Foo列表,如下所示: 因此,每个列表项都在创建一个文件流。因此,流的数量随着列表项数量的增加而增加。如何为这些流分配内存?

  • 如何在代码中检测到我处于发布模式或调试模式?

  • 当垃圾收集器运行并释放内存时,内存会返回操作系统还是作为进程的一部分保留下来。我的强烈印象是,内存实际上从未释放回操作系统,而是作为内存区域/池的一部分保留下来,供同一进程重复使用。 因此,进程的实际内存永远不会减少。提醒我的一篇文章是这样的,Java的运行时是用C/C写的,所以我想同样的事情也适用? 更新< br >我的问题是关于Java的。我提到C/C是因为我假设Java的分配/释放是由JRE

  • 我正在使用mockito作为junit。在创建对象的模拟时,我有疑问。我有一个名为DBConnect的类。我需要数据库属性,如dbname、凭据等。PatientDetails使用这个类。现在,当我为PatientDetails编写junit时。所以我使用以下代码。 用这个我不能得到正确的结果。