Java中的垃圾收集 博览会:

Java中的垃圾收集 博览会:,java,garbage-collection,Java,Garbage Collection,一般来说,引用计数的缺点是“它无法检测循环”。然而,在某些情况下,引用计数非常有用: class EmergencyPatient { DoctorPtr doctor; EmergencyPatient() { doctor = Doctor::acquire(); } ~EmergencyPatient() { Doctor::release(doctor); } }; 现在,在一个参考文献统计的世界里,一旦我们不再参考急诊病人,医生就被释放了 在Java的非refcount

一般来说,引用计数的缺点是“它无法检测循环”。然而,在某些情况下,引用计数非常有用:

class EmergencyPatient {
  DoctorPtr doctor;
  EmergencyPatient() { doctor = Doctor::acquire(); }
  ~EmergencyPatient() { Doctor::release(doctor); } 
};
现在,在一个参考文献统计的世界里,一旦我们不再参考急诊病人,医生就被释放了

在Java的非refcounted世界中,这在很大程度上取决于何时对EmergencyPatient进行垃圾收集——由于垃圾收集器是分代的,EmergencyPatient可能在较老的一代中,并且在很长一段时间内不会被收集

问题: 对我来说,医生是非常宝贵的资源;其他急诊病人需要医生。然而,对于Java来说,EmergencyPatient对象只是几个字节的内存

问题: 解决这个问题的正确方法是什么?(有一些资源我希望在知道它们不再被使用时立即释放)


谢谢

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

Doctor doctor = doctorFactory.acquire();
try
{
    EmergencyPatient  patient = new EmergencyPatient(doctor);
    doctor.examinePatient();
}
finally
{
    doctor.release();
}
顺便说一句,您会注意到,在我的实现中(就像在现实世界中一样!),患者不会选择医生。这使您能够在单元测试中为患者提供模拟医生



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

垃圾收集管理内存资源。如果需要更多内存,GC将使其可用。如果您有其他类型的资源、文件句柄、数据库连接等,您可以根据自己的喜好管理它们的生存期。

如果您检查4个引用对象,则当您的对象成为“符合垃圾收集条件”时,会有一个对象通知您。这意味着您不必等待“大”GC,它可以在一个小过程中让您知道您的对象是否变得不可访问,即使它位于旧一代区域中


我相信这应该是做你正在尝试的事情的正确方法。

你把分配资源(如医生)与分配内存混为一谈。如果内存是您宝贵的资源,那么您是对的,Java没有像其他语言那样提供细粒度的控制。没有细粒度控制的好处是,您可以从微观管理内存中解放出来,这可以提高生产率和稳定性


如果您正在管理内存以外的资源,例如,在本例中,您可以使用其他模式来确保在使用它们的对象不再需要它们时释放它们。一种方法是让患者在接受治疗时锁定医生,然后在接受治疗后释放锁定。

“参考计数”是一种异常粗糙的机制。Java的GC例程远比这强得多。引用计数的另一个问题是并发性。你打开一个巨大的蠕虫罐头,试图在有线程的情况下进行ref计数。这真是一幅想象中的画面。很高兴你喜欢它。。。它实际上是从我的原始文本中调低的:-)我从来没有理解过这个结构。它假设医生只在当前方法的时间跨度内存在。你如何在现实世界中实现这一点——例如,分配是通过GUI上的“分配”按钮完成的,释放是通过GUI页面(或另一页面)上的“释放”按钮完成的。PS:我理解这样的情况,即你的稀有资源可以在一组代码中打开、使用和关闭,但这与GC解决的问题不同,GC是一个创建实例的类,可以传递给任意数量的其他类,并在确定没有人使用它时消除它。看起来是一个完全不同的问题。@Bill-当然这取决于资源。您当然不希望在GUI的一个部分中启动数据库事务,然后在另一个部分中提交它。。。除非你想锁定你的数据库,这正是我写的。我认为java中最接近“显式”释放的是System.gc()(我不建议这样做)。即使是System.gc()也不能保证所有垃圾都被回收(它只是“尝试”根据其JavaDoc释放内存)并调用System.gc()通常是不可修改的,因为它在每个GC算法和JVM中的行为不同,并且会对应用程序的性能产生负面影响。有点像病人自己动手治疗……你怎么知道小GC的运行频率?据我所知,Java规范保证了垃圾收集的频率,尽管它不能保证——Sun最近的VM中的GC是艺术杰作。如果您使用线程收集器,那么后台运行的线程会不断评估对象的可访问性,但是是的,它依赖于GC系统,但通常应该非常快(根据我的经验,在没有线程GC的情况下,机器一空闲,事情就被释放了,我相信它应该总是即时的,但我会在你选择的VM上测试这个假设)