当前位置: 首页 > 知识库问答 >
问题:

java系统。gc()仅在隐式设置obj=null时有效?

华飞驰
2023-03-14

我在windows 10上使用jdk1.8,我有这个代码片段来测试System.gc()是如何工作的:

public class testGc{
    static class MyObject{
        @Override
        protected void finalize() throws Throwable{ // not called when System.gc()
            System.out.println("gc: " + toString());
        }
    }

    public static void main(String[] args) throws Exception{
        {
            MyObject obj=new MyObject();
            System.out.println("NOT set to null");
        }
        System.gc(); // obj still exists
        Thread.sleep(500);
    }
}

你可以在我的main()中看到,代码块结束,obj不再被引用,然后是System.gc()。我期望这个“obj”被回收。但是这个程序只打印:

NOT set to null
    public static void main(String[] args) throws Exception{
        {
            MyObject obj=new MyObject();
            System.out.println("Set to null");
            obj=null;//need this expression!
        }
        System.gc(); // now it works
        Thread.sleep(500);
    }

现在程序打印:

Set to null
gc: testGc$MyObject@2130772

为什么我需要使用“=null”来创建系统。gc()工作并调用我的“finalize”函数?代码块之后,“obj”不再有效。

如何理解这一点?谢谢

共有1个答案

南宫阳焱
2023-03-14

因为JVM不是这样工作的。

JVM(类文件)级别的局部变量不存在。相反,还有堆栈(类文件是基于堆栈的语言),任何方法都会设置固定数量的未命名“插槽”。局部变量和插槽之间只有轻微的“链接”。例如,此代码:

void example() {
 int a = 5;
 System.out.println(a);
 int b = 10;
 System.out.println(b);
}

最终将只使用一个插槽(或者可能没有任何插槽,将文本直接推到堆栈上,然后println方法将使用它们)。

不能对活动方法中仍由本地“插槽”指向的任何对象进行垃圾收集。插槽不会消失。因此,在您的示例代码中,是的,在java(语言)术语中,obj变量不再存在,但在java(虚拟机)术语中,它确实存在-该方法有一个插槽,第一个插槽指向该对象<代码>javac不会决定添加额外的代码来撤销这一事实,以帮助垃圾收集-这将导致数十亿的内存写入几乎完全无用,并将使收益相形见绌!

相反,当一个方法退出时,它的堆栈空间和那些插槽都会被重用(并被标记为不再以一种更智能的方式阻止垃圾收集,即显式地对其进行写入),对于几乎所有的意图和目的来说,这“足够快”。

这确实意味着在极其罕见的情况下,你会做这样的事情:

void example() {
  {
    List<String> list = ... make some GIGANTIC 1GB+ list ...
    process(list);
  }

  callSomeMethodThatAlsoNeedsTonsOfMemory();
}

您将遇到内存错误,明智的做法是添加一个显式的list=null 在中间。除此之外,这实际上不是真的——更好的方法是将上面写的“块”粘贴到一个方法中,然后用两个调用替换这个方法。现在不需要这样做了——事实上,包含1GB列表的方法(以及进程(列表)调用)在调用内存中的唯一可用的方法(callsomethods)开始之前结束,这意味着它的插槽被正常清除。

更进一步——制作一个巨大的列表,然后处理它,只是在之后立即进行垃圾收集,这可能是不明智的。有意义的算法少得可怕——最有可能的是,你要么想逐个单元处理这些数据(而不是生成100万条目,将它们粘贴在列表中,然后处理列表——在循环中生成1个条目,处理它,然后生成下一个,处理它,等等),或者,嘿,如果需要1GB,如果你扩展得更大一点,可能需要100GB,所以这需要一个磁盘支持的数据库解决方案。

换言之,JVM完全有意在这些特殊情况下在可能的情况下无法GC。

注意:<代码>系统。gc()只是一个请求;某种暗示。它不能保证垃圾收集会真正发生。然而,它通常是“有效的”,对你所看到的东西的解释与这个系统的事实无关。gc不是保证。

 类似资料:
  • 问题内容: 我的老板说我应该使用,因为它比更好,但是他不记得为什么这样做。有什么理由要使用吗? 我以某种方式感觉到…相反! 在Google上进行搜索后,我发现的唯一结果是: 在C语言中,它可以防止您意外地在条件结构中键入(obj = null)。 问题答案: 您不能通过输入来意外分配给它。但是,这是C时代的回忆,在Java中是不可能的,因为表达式返回赋值的右侧。由于不是,编译器会抱怨。 我会尽力向

  • 一、简介 PHPSSO可以设置禁止注册的用户名或EMAIL等。还可以整合ucenter,实现v9与uc的用户整合,实现与uc应用的同步注册、登录。还可以设置与php2008 sp4密码兼容等。 二、功能演示 1,注册配置 设置禁止注册用户名,E-MAIL等。如下图所示: 2,UCenter配置 配置好基本信息就能实现v9与uc的用户整合,实现与uc应用的同步注册、登录。如下图所示: 1,PHP20

  • 我在页面加载上有一些问题,因为页面加载了一些异步的东西,我想中断页面加载来继续我测试的下一个步骤。 我该怎么解决这个?

  • cmf_set_option($key, $data, $replace = false) 功能 设置系统配置,通用 参数 $key: string 配置键值,都小写 $data: array 配置值,数组 $replace: array 是否完全替换 返回 bool 是否成功

  • X2.2.0新增 sp_set_option($key,$data) 功能: 设置系统配置,通用 参数: $key: 配置的键名,英文下划线小写,最好加上自己的应用或插件名作为前级 $data:配置的值,数组 返回: 类型boolean,true设置成功 使用: $result = sp_set_option('portal_custom_settings',array('test'=>1));

  • 本章节介绍了分析云涉及的相关设置,包括站点的创建与管理、指定广告跟踪使用说明、用户ID策略的使用。 指定广告跟踪支持监测第三方广告来源,可辅助渠道优化与营销决策。 用户ID策略为全端平台提供了唯一的用户标识,能够适配用户跨平台、跨设备等复杂的业务分析场景。 系统设置主要包含以下内容: 站点管理 指定广告跟踪 用户ID策略说明