不理解java中对象的范围(java新手混淆)



这个问题是基于用Java思考,第2版,第109页对象的范围一章,它说当我们使用创建Java对象时,它会挂在范围的末尾。它给出了这个例子:

{ 
  String s = new String("a string"); 
} /* end of scope */ 

然后它说,

引用s在作用域末尾消失。然而s所指向的字符串对象仍在占用内存。在里面这段代码,无法访问对象,因为仅引用它就超出了范围。

因此,如果我理解正确,文本"字符串"仍然存在于内存中,但具有第一个字符"a"的内存地址的指针不存在。这就是它的意思吗?

它接着说,

事实证明,因为使用新创建的对象将保留为只要你想要它们,一大堆C++编程问题简单地在Java中消失。

为什么这是有利的?在上面的例子中,字符串数据继续驻留在内存中,无法访问它(因为指针在超出范围后被销毁),这只会消耗资源。

简单地说,段中参考变量s的范围:

{ 
  String s = new String("a string"); 
} /* end of scope */ 

在支架之间。这意味着s仅存在于打开和关闭{}之间。然而,那个街区发生了一些事情。

在大括号中,调用new运算符来创建String对象的实例。为对象分配内存,并将对该对象的引用分配给变量s

在代码块的末尾,s不再存在,因此它所持有的引用也不再存在。然而,String对象仍然存在于内存中。但是,由于不再有任何变量引用它,因此程序的任何部分都无法访问它。此时,对象有资格进行垃圾收集。

在对象被垃圾收集之前,它仍然占据系统内存中的一个位置,即使程序不再可以访问它。

一旦Object离开scope,它将准备好进行垃圾收集,直到GC收集分离的对象,它将占用内存。

转到第215页了解垃圾收集器的工作原理

Java代码运行时,垃圾回收器会定期运行,以查找所有未被引用的对象,并释放它们占用的内存。发生这种情况时,会对对象调用finalize方法(如果已定义)。此时,您将执行对象所需的任何清理操作。

使用c++时,您必须担心使用delete关键字自己释放内存,否则可能会导致内存泄漏。

使用Java,您可以用内存分配管理换取托管对象生命周期管理。

在Java垃圾回收器为您清理之前,它一直驻留在内存中。它会定期这样做。这意味着你不必自己管理记忆。

您可以创建对象,而不必担心分配和释放内存。

由于对象超出范围,java垃圾收集器将自动对其进行垃圾收集。这对C++来说是有利的,因为在java中,java Runtime会自动处理垃圾回收,所以最终会回收内存。C++的情况并非如此

在Java中,一旦对对象的所有引用都为null或超出范围,对象本身就会成为垃圾收集器销毁的候选者。GC根据自己的算法自动执行此操作,而在C++中,您必须显式销毁对象。此外,由于所谓的实习,字符串可能会继续存在。

我不明白这本书在谈到仍占用内存的代码块时试图表达的观点。也许它想说的是,仅仅因为引用变量(如示例中的s)超出了范围,并不意味着内存被立即释放。它没有说明的是(至少在你发布的内容中),这样的内存会受到自动垃圾收集的影响,事实上,你应该像收集这样的孤立内存块一样进行编程。

与C++相比,Java中垃圾收集的优点在于它都是自动完成的。当对内存分配的所有强引用(包括所有间接引用)超出范围时,该内存块将自动进行垃圾回收。简而言之就是这样。Java正确地处理循环引用之类的事情,并将垃圾收集任意复杂的数据结构,前提是该结构不能直接或间接地从仍在作用域中的任何引用值访问。

此外,由于实习的原因,字符串有一些特殊的规则,所以这本书在这个例子中有点失败了。

意思是对象没有"躺在"内存中,它仍在等待垃圾收集器收集。这样想吧。你家里有很多东西,你想扔掉一些,保留一些。你有一个垃圾收集者来你家处理不需要的物品,但为了让他区分你想保留的物品和你想丢弃的物品,你需要在他到达时标记你想让他收集的物品。这就是垃圾收集器的工作方式。首先,它标记所有不需要的对象,然后一次收集所有对象。垃圾收集器经常运行。

最新更新