这个问题是基于用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正确地处理循环引用之类的事情,并将垃圾收集任意复杂的数据结构,前提是该结构不能直接或间接地从仍在作用域中的任何引用值访问。
此外,由于实习的原因,字符串有一些特殊的规则,所以这本书在这个例子中有点失败了。
意思是对象没有"躺在"内存中,它仍在等待垃圾收集器收集。这样想吧。你家里有很多东西,你想扔掉一些,保留一些。你有一个垃圾收集者来你家处理不需要的物品,但为了让他区分你想保留的物品和你想丢弃的物品,你需要在他到达时标记你想让他收集的物品。这就是垃圾收集器的工作方式。首先,它标记所有不需要的对象,然后一次收集所有对象。垃圾收集器经常运行。