为什么 Finalize() 仅在创建新对象后执行,而不是在调用 gc() 后执行?

2024-02-18

调用 gc() 时,finalize() 不应该立即执行吗?输出结果的顺序有点不太令人信服。

class Test
{
    int x = 100; 
    int y = 115;

    protected void finalize()
    {System.out.println("Resource Deallocation is completed");}
}

class DelObj
{
    public static void main(String arg[])
    {
        Test t1 = new Test();           
        System.out.println("Values are "+t1.x+", "+t1.y+"\nObject refered by t1 is at location: "+t1);
        t1 = null; // dereferencing
        System.gc(); // explicitly calling

        Test t2= new Test();
        System.out.println("Values are "+t2.x+", "+t2.y+"\nObject refered by t2 is at location: "+t2);

    } 
}

得到新对象创建后finalize()的执行结果,由t2引用:

D:\JavaEx>java DelObj
Values are 100, 115
Object refered by t1 is at location: Test@6bbc4459
Values are 100, 115
Object refered by t2 is at location: Test@2a9931f5
Resource Deallocation is completed

Calling System.gc()仅向 JVM 提供提示,但不保证实际的垃圾收集将会发生。

然而,与您的期望相比,更大的问题是垃圾收集与终结不同。

参考 Java 6 文档,System.gc() https://docs.oracle.com/javase/6/docs/api/java/lang/System.html#gc() states:

运行垃圾收集器。

调用 gc 方法表明 Java 虚拟机会努力回收未使用的对象,以使它们当前占用的内存可供快速重用。 ……

相比于System.runFinalization() https://docs.oracle.com/javase/6/docs/api/java/lang/System.html#runFinalization():

运行任何挂起终结的对象的终结方法。

调用此方法表明 Java 虚拟机花费精力来运行已发现已被丢弃但尚未运行其 Finalize 方法的对象的 Finalize 方法。 ……

因此,可能存在“等待最终确定”的情况。 “已发现已被丢弃但其 Finalize 方法尚未运行的对象”。

不幸的是,Java 6 的文档finalize() https://docs.oracle.com/javase/6/docs/api/java/lang/Object.html#finalize()从误导性的句子开始:

当垃圾收集确定不再有对该对象的引用时,由该对象的垃圾收集器调用。

而垃圾收集和终结是两个不同的事情,因此,finalize()方法是not由垃圾收集器调用。但请注意,后续文档说:

Java 编程语言不保证哪个线程将调用finalize任何给定对象的方法。

因此,当你说“输出结果的顺序有点令人难以置信”时,请记住我们在这里讨论的是多线程,因此在没有额外同步的情况下,顺序is在你的控制之外。

Java 语言规范 https://docs.oracle.com/javase/specs/jls/se6/html/execution.html#12.6甚至说:

Java 编程语言没有指定多久将调用终结器,只是说它将在重用对象的存储之前发生。

以及后来

Java 编程语言对 Finalize 方法调用没有强加任何顺序。终结器可以按任何顺序调用,甚至可以同时调用。

实际上,垃圾收集器只会将需要终结的对象放入队列,而一个或多个终结器线程轮询队列并执行finalize()方法。当所有终结器线程都忙于执行特定的finalize()方法时,需要终结的对象队列可能会增长任意长。

请注意,现代 JVM 对那些没有专用的类进行了优化finalize()方法,即继承该方法Object或者只有一个空方法。这些类的实例(所有对象中的大多数)会跳过此终结步骤,并且它们的空间会立即被回收。

所以如果你添加了一个finalize()方法只是为了找出对象何时被垃圾回收,这就是它的存在finalize()减慢内存回收过程的方法。

所以最好参考 JDK 11 版本finalize() https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Object.html#finalize():

Deprecated.

最终确定机制本质上是有问题的。最终确定可能会导致性能问题、死锁和挂起。终结器中的错误可能导致资源泄漏;如果不再需要,则无法取消最终确定;并且不同对象的 Finalize 方法的调用之间没有指定顺序。此外,我们无法保证最终确定的时间。仅在无限期延迟(如果有)之后才可以对可终结对象调用 Finalize 方法。实例持有非堆资源的类应该提供一种方法来显式释放这些资源,并且如果合适,它们还应该实现 AutoCloseable。 Cleaner 和 PhantomReference 提供了更灵活、更有效的方法来在对象变得无法访问时释放资源。

因此,当您的对象不包含非内存资源,因此实际上不需要终结时,您可以使用

class Test
{
    int x = 100;
    int y = 115;
}

class DelObj
{
    public static void main(String[] arg)
    {
        Test t1 = new Test();
        System.out.println("Values are "+t1.x+", "+t1.y+"\nObject refered by t1 is at location: "+t1);
        WeakReference<Test> ref = new WeakReference<Test>(t1);
        t1 = null; // dereferencing
        System.gc(); // explicitly calling
        if(ref.get() == null) System.out.println("Object deallocation is completed");
        else System.out.println("Not collected");

        Test t2= new Test();
        System.out.println("Values are "+t2.x+", "+t2.y+"\nObject refered by t2 is at location: "+t2);

    }
}

The System.gc()call still 只是一个提示,但在大多数实际情况下,您会发现您的对象随后被收集。请注意,为对象打印的哈希代码,例如Test@67f1fba0与内存位置无关;这是一个顽强的神话。对象内存地址背后的模式通常不适合hashing,此外,大多数现代 JVM 可以在对象的生命周期内将对象移动到不同的内存位置,而身份哈希码保证保持不变。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 Finalize() 仅在创建新对象后执行,而不是在调用 gc() 后执行? 的相关文章

  • .NET 任务实例在运行期间是否会超出范围?

    如果我在方法中有以下代码块 使用 NET 4 和任务并行库 var task new Task gt DoSomethingLongRunning task Start 并且该方法返回 该任务是否会超出范围并被垃圾收集 或者是否会运行完成
  • GC.Collect()

    好吧 我已经读过几个有关它的主题 但就这样吧 假设我有一个应用程序 基本上我会时不时地单击一个按钮 几分钟内会发生很多事情 然后它可能会再空闲一个小时 或者可能只是一分钟 在这一切结束之后 调用 GC Collect 不是一个很好的情况吗
  • 当日志显示大量GC命中时,我们需要更改哪些代码?

    当日志显示大量垃圾收集命中时 我们需要更改哪些代码 我们需要释放一些对象吗 我们会通过对象重用来加速代码吗 EDIT 我针对很多名称运行此代码 public static String removeAccents String s if s
  • 从 Java 6 升级到 Java 7 后 Kerberos 损坏

    我有一个使用 spring security kerberos 扩展的工作应用程序 在 jboss 上运行 运行 java 6 我正在将 jvm 从 java 6 升级到 java 7 当我这样做时 使用与 java 6 相同的代码库和相同
  • 为什么要实现finalize()?

    我已经阅读了很多 Java 新手问题finalize 令人困惑的是 没有人真正明确表示 Finalize 是一种不可靠的清理资源的方法 我看到有人评论说他们用它来清理连接 这真的很可怕 因为接近保证连接关闭的唯一方法是最后实现 try ca
  • Application.Run 处的 CallbackOnCollectedDelegate(new Form1())

    我制作了一个非常小的应用程序 使用 SlimDX 捕获游戏中的屏幕 我按左键捕获 捕获有效 至少当我单击表单本身时 但是一旦我单击 Firefox 或任何其他应用程序 我就会收到此异常 对 CaptureScreen CaptureScre
  • 相当于.net中的SoftReference?

    我熟悉WeakReference 但我正在寻找一个已清除的引用类型only当内存不足时 不仅仅是每次运行 gc 时 就像 Java 的SoftReference 我正在寻找一种实现内存敏感缓存的方法 ASP NET 缓存为您提供了所需的内存
  • 调用 GC.Collect 和 GC.WaitForPendingFinalizers 时会发生死锁吗?

    鉴于以下情况 GC Collect GC MaxGeneration GC WaitForPendingFinalizers GC Collect GC MaxGeneration 考虑到多线程和垃圾收集模式 什么情况下会出现死锁WaitF
  • 使用套接字时避免垃圾收集

    在我的一个游戏项目中 我尽力避免创建对象 从而阻止垃圾收集器运行 这是一个网络游戏 我主要发送数据的字节数组 但也发送一些其他对象 例如 int 数组 我在分析 Eclipse 中的内存分配时注意到 通过我向套接字写入 读取的方式 在我的程
  • 正确结束 Java 命令行应用程序

    我只是想知道 我需要打电话吗System exit 0 就在之前mainJava 命令行应用程序的方法结束了吗 如果是这样 为什么 如果我总是放在那里 与让它自行退出有什么区别0 什么没清理干净 提前致谢 不 您并不总是需要打电话Syste
  • ListView 与 getView() 由于不断的 GC 而变得缓慢?

    我的应用程序中有一个 ListView 并且我已经重写了 getView 方法 因此我可以根据行的文本更改行的 ImageView src 问题是 我注意到 ListView 滚动滞后 当我检查 DDMS 时 似乎每次滚动 ListView
  • 如何让 G1 打印更多日志详细信息?

    我正在测试基于 Jetty 的 API 与基于 Netty 的 API 实验中唯一的区别是我使用哪个 API 相同的应用程序 相同的服务器 相同的内存配置 相同的负载等 我使用基于 Netty 的 API 时会得到更长的 GC 暂停 大多数
  • C# 和 .Net 垃圾收集器性能

    我正在尝试用 C 和 NET 制作游戏 并且计划实现更新游戏世界中游戏对象的消息 这些消息将是 C 引用对象 我想要这种方法 因为如果我希望游戏是多人游戏 那么通过网络发送它们会更容易 但是如果我有很多消息 对于垃圾收集器来说不是压力很大吗
  • 这个作用域/闭包什么时候在 javaScript 中被垃圾回收?

    我正在做一门课程 该课程正在讨论范围 闭包并简要提到垃圾收集 课程中提出一个问题 范围保持多久 答案是 直到 不再有任何提及它 是的 所以我们基本上说的是 是的 闭包有点像对隐藏范围对象的引用 所以只要有一些函数仍然有一个闭包 范围 该范围
  • numpy.ndarray 对象不被垃圾回收

    在尝试微调某些 C C 函数的 Python 绑定中的一些内存泄漏时 我发现了一些与 Numpy 数组的垃圾收集相关的奇怪行为 为了更好地解释这种行为 我创建了几个简化的案例 该代码是使用memory profiler 其输出紧随其后 当涉
  • 运行“git gui”时如何跳过“松散对象”弹出窗口

    当我运行 git gui 时 我会看到一个弹出窗口 上面写着 This repository currently has approximately 1500 loose objects 然后它建议压缩数据库 我之前已经这样做过 它将松散对
  • Java G1 GC 处理引用对象运行缓慢

    我已经在 J ava 上运行了计数器 它24小时工作 每秒点击通过100次左右 白天 GC 处理时间从 20 60 毫秒缓慢上升到 10000 60000 毫秒 然后下降到 20 60 毫秒 这种模式不时地重复 从 GC 日志中我发现 GC
  • 对象什么时候有资格进行垃圾收集?

    在下面的代码中 考虑到amethod已被调用 最初引用的对象在什么点 线上myObject 有资格进行垃圾收集吗 class Test private Object classObject public void amethod Objec
  • 垃圾收集器如何在幕后工作来收集死对象?

    我正在阅读有关垃圾收集的内容 众所周知 垃圾收集会收集死亡对象并回收内存 我的问题是 Collector 如何知道任何对象已死亡 它使用什么数据结构来跟踪活动对象 我正在研究这个问题 我发现GC实际上会跟踪活动对象 并标记它们 每个未标记的
  • Kotlin super.finalize()

    当迁移到Kotlin from Java我遇到了一个问题 我覆盖了Object s finalize method Override protected void finalize throws Throwable stopTimer su

随机推荐

  • 在多维数组中搜索某些值

    我有一个以下格式的多维数组 0 id gt 1 type gt fish owner gt bob 1 id gt 2 type gt cat owner gt mary 2 id gt 3 type gt dog owner gt lar
  • 通过 GitHub API 访问链接的 SAML 身份

    我想使用 GitHub API 任何版本 获取组织中 GitHub 登录名和电子邮件之间的映射 我可以使用以下 GraphQL 查询获取组织成员帐户上的电子邮件 query organization login myorg members
  • 如果 SSIS 中的值为 NULL,则条件拆分失败

    我根据以下规则将完整外连接的结果传递给条件拆分和过滤记录 基本上两个表具有相同的架构 并且主键值相同 a If Primary key of Source is NULL b If Primary Key of Destination is
  • MySQL:按块检索大选择

    我已经选择了更多 7000 万行 我想将选定的数据保存到一个大的csv文件于win2012 R2 问 如何从 MySQL 中按块检索数据以获得更好的性能 因为当我尝试保存一个我得到的大选择时 内存不足错误 您可以尝试使用LIMIT特征 如果
  • 存储和检索 SHA-256 散列和加盐密码的正确方法

    这是我第一次尝试安全地存储密码 我想确保一切都正确完成 建议我将 SHA 256 哈希与 salt 一起使用 假设用户通过表单提交了密码 我们通过以下方式获取密码 password POST password 对 password 加盐并对
  • ASP.NET MVC 和 IIS 5

    让 ASP NET MVC 应用程序托管在 IIS 5 6 或 7 上运行的最佳方法是什么 当我尝试发布 ASP NET MVC 应用程序时 我收到的似乎只是 404 错误 我做了一些谷歌搜索并找到了一些解决方案 但看起来都不是超级优雅 而
  • 如何从 Jena API Eclipse 项目启动 Fuseki 服务器?

    您好 我也是语义 Web 域和 Apache Jena 环境的新手 这就是我发布此问题的原因 我有一个使用 Jena API 的项目 当我运行它时 它会在控制台中显示输出 我确实从命令行运行了 Fuseki 服务器 它作为本地服务器运行 我
  • 运行 crontab 时出现权限被拒绝错误[重复]

    这个问题在这里已经有答案了 我在文件夹 csv file 中创建了一个 r 脚本 marc Marc Linux csv file ls 8388 26580527145 csv csv file Rproj excel source wr
  • Spark Dataframes UPSERT 到 Postgres 表

    我正在使用 Apache Spark DataFrames 来连接两个数据源并将结果作为另一个 DataFrame 获取 我想将结果写入另一个 Postgres 表 我看到这个选项 myDataFrame write jdbc url ta
  • Postman - 使用密钥文件进行 JWT 身份验证

    我正在尝试使用 Postman 来测试在 Google Cloud Platform 上开发的 API API 端点后面的 App Engine 我有 JSON 格式的密钥文件 type service account project id
  • BlackBerry 是否支持其应用程序开发人员的演示/测试版?

    我有兴趣为 BlackBerry 设备开发应用程序 想知道他们是否支持应用程序开发人员的演示版或测试版概念 我的意思是能够将我的应用程序的测试版或演示版部署给有限 受限的受众 例如业务合作伙伴 客户 外部测试人员等 他们中没有任何内容测试和
  • ASP.NET MVC - 如何抛出类似于 StackOverflow 上的 404 页面

    我目前有一个继承自的 BaseController 类System Web Mvc Controller 在那堂课上我有HandleError将用户重定向到 500 哎呀 我们搞砸了 页面的属性 目前这正在按预期进行 这有效
  • 让标签参与控制选项卡

    我有继承自的自定义控件Label并且有ControlStyle Selectable set to true 当用户单击该控件时 该控件将获得焦点 但如果用户从另一个控件进行选项卡 则不会获得焦点 即使当我有一个仅由该类型的控件填充的表单时
  • Reactjs 光滑的幻灯片

    我正在使用reactjs制作一个非常简单的滑块reactstrap 引导程序 工作示例 https codesandbox io s compassionate brook fz5mm https codesandbox io s comp
  • 尝试找出从 Firestore 字典中删除元素的更好方法

    我在应用程序中使用 Firestore 并且有一个名为 投票 的地图字段 用于显示用户的赞成票或反对票 它看起来像这样 我想添加一个选项来从那里删除元素 这就是我现在得到的 getting the user s votes dictiona
  • 将光标后的文本移动到新行

    我是 Vim 新手 我在 OSX Snow Leopard 上使用 MacVim 我必须采取的最常见操作之一是将光标移动到新行 并将光标后面的文本移动到新行 我知道在正常或可视模式下按 o 会将光标移动到新行并切换模式以进行插入 我想做的是
  • 注入和资源以及自动装配注释

    有什么区别 Inject and Resource and Autowired注释 我们什么时候应该使用它们 Inject Autowire Resource 之间的区别 自动连线 spring propriety 注解 与 Inject
  • 清除 Coldfusion 生产服务器中的缓存

    我正在使用 CFMX 并且存在一个问题 变量 yy 在 yyfiling 中未定义 这是生产中的一个问题 我正在推动对其进行更正 但它们似乎没有出现在服务器上 我想清除服务器缓存 以便我升级的代码可以生效 CFAdmin 生产模板已被缓存
  • 如何使用 protobuf-net 序列化/反序列化大型项目列表

    我有大约 5 亿个项目的清单 如果我序列化单个项目而不是列表 我可以将其序列化为带有 protobuf net 文件的文件 我无法将项目收集到价格列表中然后序列化 因为我耗尽了内存 因此 我必须一次序列化一条记录 using var inp
  • 为什么 Finalize() 仅在创建新对象后执行,而不是在调用 gc() 后执行?

    调用 gc 时 finalize 不应该立即执行吗 输出结果的顺序有点不太令人信服 class Test int x 100 int y 115 protected void finalize System out println Reso