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

Java局部变量什么时候可以使用GC?

高慈
2023-03-14
问题内容

给定以下程序:

import java.io.*;
import java.util.*;

public class GCTest {

    public static void main(String[] args) throws Exception {
        List cache = new ArrayList();
        while (true) {
            cache.add(new GCTest().run());
            System.out.println("done");
        }
    }

    private byte[] run() throws IOException {
        Test test = new Test();
        InputStream is = test.getInputStream();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buff = new byte[256];
        int len = 0;
        while (-1 != (len = is.read())) {
            baos.write(buff, 0, len);
        }
        return baos.toByteArray();
    }

    private class Test {
        private InputStream is;

        public InputStream getInputStream() throws FileNotFoundException {
            is = new FileInputStream("GCTest.class");
            return is;
        }

        protected void finalize() throws IOException {
            System.out.println("finalize");
            is.close();
            is = null;
        }
    }
}

您是否希望在run方法中的while循环仍在执行且局部变量test仍在范围内时调用finalize?

更重要的是,此行为在任何地方都有定义吗?Sun有什么声明它是实现定义的吗?

这与以前人们在主要关注内存泄漏的SO上提出此问题的方式相反。在这里,我们让GC积极地对变量感兴趣的变量进行GC处理。您可能会因为测试仍在“范围内”而不会被GC,所以您可能会期望这样做。

作为记录,似乎有时测试“有效”(即最终命中了OOM),有时失败,具体取决于JVM的实现。

BTW不能捍卫这段代码的编写方式,这只是工作中出现的一个问题。


问题答案:

如果对象仍然在范围内,则不会对其进行垃圾回收,但是,如果代码中实际上并未进一步使用该变量(因此您看到的是不同的行为),即使在以下情况下,JIT编译器也可能会将其超出范围:您阅读源代码后,该变量似乎仍在“范围内”。

我不明白为什么您不在乎是否在代码中不再引用对象,但是如果您要确保对象保留在内存中,最好的方法是直接在类的字段中引用它们,甚至在静态领域也更好。如果静态字段引用了该对象,则不会收集垃圾。

编辑:这是您正在寻找的显式文档。

>我假设一个对象 本地引用超出范围 之前 无法死亡。

不能假定。Java规范和JVM规范都不对此提供保证。

仅仅因为变量在范围内,并不意味着它指向的对象是可到达的。通常情况下,范围内变量指向的对象是可访问的,但您的情况并非如此。编译器可以在jit时确定哪些变量已死,并且在oop-
map中不包含此类变量。由于可以从任何活动变量中访问“ nt”所指向的对象,因此可以进行收集。



 类似资料:
  • 问题内容: 什么时候应该使用ThreadLocal变量? 如何使用? 问题答案: 一种可能的(并且是常见的)用法是,当你有一些不是线程安全的对象,但又希望避免同步对该对象的访问时(我正在看着你,SimpleDateFormat)。而是给每个线程自己的对象实例。 例如:

  • 问题内容: 我发现了一些参考(例如),它们建议尽可能多地使用它,我想知道这有多重要。这主要是在方法参数和局部变量的上下文中,而不是最终方法或类。对于常量,这很明显。 一方面,编译器可以进行一些优化,使程序员的意图更加清晰。另一方面,它增加了冗长性,并且优化可能微不足道。 我需要努力记住的东西吗? 问题答案: 最终字段-将字段标记为最终字段会强制它们在构造结束时进行设置,从而使该字段引用不变。这样可

  • 问题内容: 在什么情况下,您将使用字段变量而不是局部变量?我发现很难决定何时在类中的2个或更多方法中使用变量。我倾向于使用局部变量,并将它们传递给另一种方法。 谢谢, 莎拉 问题答案: 用面向对象的术语来说,变量作为对象的属性有意义吗?如果是这样,则应将其设为字段变量。如果没有,它可以任意选择。 记住单一责任原则-设计良好的班级应该只承担1个责任,因此只有1个改变的理由。

  • 已弃用。这种方法本质上是不安全的。使用thread.Stop停止线程会导致它解锁它锁定的所有监视器(作为未检查的ThreadDeath异常向堆栈上传播的自然结果)。如果以前由这些监视器保护的任何对象处于不一致的状态,则损坏的对象将对其他线程可见,从而可能导致任意行为。stop的许多用法应该被简单修改某个变量以指示目标线程应该停止运行的代码所取代。目标线程应该定期检查这个变量,如果变量指示它要停止运

  • 我想问一个问题,什么时候在Java中使用静态变量/方法或实例变量/方法更有利? 我知道这取决于特定的情况(比如将util类编程为静态方法),但是我们能声明一些像通用策略一样的东西吗?

  • 问题内容: Java的设计者是否有任何理由认为不应为局部变量提供默认值?认真地讲,如果实例变量可以被赋予默认值,那为什么我们不能对局部变量做同样的事情呢? 问题答案: 声明局部变量主要是为了进行一些计算。因此,程序员决定设置变量的值,并且不应采用默认值。如果程序员错误地没有初始化局部变量并且使用默认值,则输出可能是一些意外值。因此,在使用局部变量的情况下,编译器将要求程序员在访问变量之前使用一些值