如何销毁Java对象?

7
我开发了一个使用多个对象关系的Java应用程序,导致内存使用过于昂贵。由于应用程序设计使销毁对象并重新利用先前清除的空间变得困难,因此我没有管理Java内存的经验。例如,我正在使用Observer和MVC模式。
理论上说,如果一个对象不可从任何活动线程或静态引用访问,则该对象将成为垃圾回收或GC的候选对象。换句话说,如果一个对象的所有引用都为空,则该对象将成为垃圾回收的候选对象。
但是,在我的短暂经验中,当你有像我这样的场景时(即你不知道你的类存在多少引用),从我想要从内存中删除的对象中销毁所有引用变得非常困难(例如,当关闭一个帧时)。
根据这种情况,当一个对象有多个引用时,我该如何处理它的销毁?或者在彼此之间具有复杂引用时,我需要如何管理内存?
5个回答

18

跟踪

根据这种情况,当有多个引用时,我该如何处理对象销毁?

确保这些引用不再需要。

如果您将它们隔离开来,即使是在一个大的孤立的图形中,这些未使用的对象不再与您的主程序连接在一起,那么它们都有资格进行垃圾回收

如果局部变量已经到达其作用域的末尾(并且其包含的对象也是如此),则它们将有资格进行垃圾回收,如果它们没有与其他任何东西“链接”(添加到集合、复合等)。对于 UI 对象,在对象图方面确实很难理解,请确保正确处理它们或阅读文档以确保它们会自然地被处理。

Simplified View of Reference Counting in the JVM

"别碰[GC]!!"

当你的对象互相引用时,我需要如何管理内存?

你无法“管理”内存。你只能管理引用。思路是通过简单地不拥有对它们的引用来“切断”与对象的连接。这样它们会保留在内存中,直到GC将它们消除。

不要试图干预GC以强制它执行操作。它是一种相当聪明的机制,尽管你可以尝试指示它显式地响应某些请求,但它可能会忽略你,这通常是个坏主意:通常不要调用GC,避免使用finalizers和显式空值如果你不理解它们的影响


回复你的评论:

简单地将一个已添加到多个集合或组合中的对象的引用设为null,并不能使其有资格被垃圾收集。这样做,你只会将一个引用设为空

你需要从所有包含对该对象引用的列表或容器中删除此对象(基本上是使它们“忘记”关于该对象的信息)。一旦没有对象仍然“记得”或具有对你创建的对象的“链接”,它就成为了垃圾收集器图表中的一个孤独的项目,从而使它成为删除的候选项。

也许听起来很繁琐,但如果你从手动管理内存的语言(比如C或C++)的角度考虑,释放和设置指向动态分配对象的指针的值确实会销毁它们,但你仍然需要从列表(或任何容器)中删除元素,否则它们将像空桶一样出现在一个空指针中。


更多阅读


1
@manix:不会的。那只会将当前作用域中命名为“object”的引用置空。你需要确实地从所有这些列表或其他容器中删除此对象。 - haylem
@halem 多个ArrayList是短期使用还是长期存在?如果它们是短期使用的,那就没有问题。当ArrayList不再可达时,垃圾收集器会自动处理。然而,如果ArrayList是长期存在的,除非你采取一些措施,否则其所有元素将在其生命周期内都是可达的。我建议使用短期使用的ArrayList。 - emory
@manix:由于您似乎是Stack Overflow上的新手,如果这个答案(和其他答案)帮助了您并回答了您的问题,您应该为它们投票支持(使用每个答案左侧的向上箭头),并接受最正确地回答您问题的答案(使用每个答案左侧的“勾”符号)。当然,我不是说您现在必须这样做,您可以给自己时间作出决定并等待更多答案。 - haylem
谢谢大家!我明白了 :) - manix
@LuiggiMendoza:谢谢。很高兴你喜欢它。 - haylem
显示剩余3条评论

6

Java垃圾回收的整个意义在于你不需要做任何事情,垃圾回收会替你完成。


别说了,哈哈。针对你的情况,我理解你为什么担心。但是可以这样想,有两种情况。第一种,编写你所使用代码的开发者没有记录可能存在的内存泄漏问题,除了使用其他东西外,你没有很多选择。第二种情况,你阅读文档并且避免了所述问题。因此,一般不要太担心,除非你怀疑某些代码正在减缓你的应用程序。 - Andy
要删除其引用,可以考虑使用像@Martinsos所说的“代理”方法吗? - manix

1

将您希望GC收集的每个引用分配给null


如果 obj 包含正在运行的线程对象或 Timer,是否执行相同的操作? - suiwenfeng

1
你可以创建一个中间类来解决问题。例如,如果你有一个类A的实例,它有很多引用,但你想要删除它,但是由于有很多引用,所以这变得困难了,你可以这样做:创建一个类B的实例,它除了包含对类A实例的引用(像某种代理)之外什么都不包含。现在你将有很多对类B实例的引用,但只有一个对类A实例的引用,你可以轻松地删除它,垃圾收集器将收集类A的实例。
图像显示使用代理(类B的实例)时的差异:现在只需要删除一个引用。

enter image description here


0

大多数情况下,垃圾回收器会在适当的时间内完成其任务。

有时您可能需要这样一种情况,即视图正在观察模型,您想要放弃视图但保留模型。在这种情况下,您需要记住观察器回调对象,并在丢弃视图时删除它们。您不一定需要为每个观察者设置特殊字段-一个取消注册每个回调的任务集将足够。或者,更复杂地,您可以具有在模型上方具有瞬态间接层,该层与底层一起解压缩。我建议避免使用各种奇怪的弱引用之类的东西。

在您可能具有终止器(或需要某种弱映射驱逐)的情况下,例如java.awt.Frame,您可能需要在资源和内存占用之间添加一层间接层,该层可以简单地被置空。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接