Java中的垃圾收集

3

说明:

通常情况下,引用计数有一个弱点,“它无法检测循环引用”。但是,在某些情况下,引用计数确实非常有用:

class EmergencyPatient {
  DoctorPtr doctor;
  EmergencyPatient() { doctor = Doctor::acquire(); }
  ~EmergencyPatient() { Doctor::release(doctor); } 
};

现在,在一个引用计数的世界中,只要我们不再引用 EmergencyPatient,医生就会被释放。
在Java的非引用计数世界中,这在很大程度上取决于何时对EmergencyPatient进行垃圾回收——由于垃圾回收器是分代的,EmergencyPatient可能在较老的一代中,并且长时间不被回收。
问题:
对我来说,医生是非常珍贵的资源;其他 EmergencyPatient 需要医生。然而,对Java来说,EmergencyPatient 对象只是几个字节的内存。
问题:
如何解决这个问题?(有些资源我希望它们在不再使用时尽快释放)。
谢谢!

"引用计数"是一种非常原始的机制。Java的GC例程比那要强得多。 - skaffman
1
另一个与引用计数相关的问题是并发性。在存在线程的情况下,尝试进行引用计数会引发一系列棘手的问题。 - Trevor Harrison
4个回答

4

在Java框架中解决这个问题的正确方法是使用try-finally结构:

Doctor doctor = doctorFactory.acquire();
try
{
    EmergencyPatient  patient = new EmergencyPatient(doctor);
    doctor.examinePatient();
}
finally
{
    doctor.release();
}

顺便提一下,在我的实现中(就像在现实世界中一样!),病人不会选择医生。这使你可以在单元测试中向病人提供模拟医生。


编辑:远离制造类,这是你应该为每个java.sql.Connection、每个java.io.InputStream或任何其他管理非内存资源的对象使用的结构。


1
“+1” 只是为了 “mock doctors” 这个词组。这真是个印象深刻的场景描绘。 - Michael Myers
很高兴你喜欢它...实际上这是我原来文本的简化版 :-) - kdgregory
@Bill - 当然这取决于资源。你肯定不想在GUI的一个部分开始一个数据库事务,然后在另一个地方提交它...除非你想要锁定你的数据库。 - kdgregory
@Bill #2 - 另一方面,OP的情境实际上反映了一种可能会在一个地方分配资源并在另一个地方释放资源的情况:您的应用程序可能是医生的病历本。在这种情况下,无论是Java、C++还是任何其他语言中都没有适当的语言级构造。 - kdgregory
(实际上,上述最后一句话并不完全正确:在Actor模型中,您可以采用“消耗或向前传递”的消息处理方式,而使用try-finally语句通常已经足够了) - kdgregory
显示剩余3条评论

3
您把分配资源(例如医生)与分配内存混淆了。如果您的宝贵资源是内存,那么您是正确的,Java无法像其他语言一样给您提供精细的控制。您因没有这种精细的控制而获得的好处是,您不需要微观管理内存,这可以提高生产力和稳定性。
如果您正在管理除内存以外的其他资源,例如在本例中的医生,您可以使用其他模式来确保当不再需要使用它们的对象时可以释放它们。一种方法是在治疗期间让患者锁定医生,然后在治疗完成后释放锁定。

正是我正在写的内容。我认为在Java中最接近“显式”释放内存的方法是System.gc()(但我不建议这样做)。 - 3lectrologos
即使是 System.gc() 也不能保证所有垃圾都被回收(根据其 JavaDoc,它只是“尝试”释放内存)。 - meriton
调用System.gc()通常是不可取的,因为它在每个GC算法和JVM中的行为不同,并且可能会对应用程序的性能产生负面影响。有点像患者自己动手治疗一样... - Jamie McCrindle

0

垃圾回收管理内存资源。如果需要更多的内存,GC将使其可用。如果您有其他类型的资源,例如文件句柄、数据库连接等,您可以自行管理这些资源的生命周期。


0
如果您检查4个参考对象,其中一个将在您的对象变为“可垃圾回收”时通知您。这意味着您不必等待“大型”GC,即使在较旧的生成区域之一,它也可以在其中一个次要传递期间通知您对象是否已变得不可访问。
我相信这应该是您尝试做的正确方式。

那你如何知道Minor GC的运行频率呢?据我所知,Java规范并没有对垃圾回收的频率做出保证。 - meriton
尽管它没有任何保证,但Sun最近的VM中的GC是艺术杰作。如果您使用线程收集器,则后台运行常量评估对象的可达性的线程,但是,它取决于GC系统,但通常应该非常快(根据我的经验,没有线程GC时,机器空闲时立即释放物体,带有GC时我相信它应该总是瞬间完成,但我会在您选择的VM上测试这个假设)。 - Bill K

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