如何在德尔福开始构建可搜索的垃圾收集器(2009-2010)

时间:2010-01-26 06:27:04

标签: delphi garbage-collection delphi-2009 delphi-2010

我正在寻找一种方法来控制我在用Delphi编写的应用程序中创建的所有业务对象。

正如关于Embarcadero的EDN(http://edn.embarcadero.com/article/28217)的文章所述,基本上有三种方法可以做到这一点。我最感兴趣的是使用接口的最后一个。这样,当业务对象不再被应用程序中的任何地方引用时,它将被处理内存(我将在稍后回到这一部分)。

在创建新的业务对象时,最好先询问新的对象管理器是否已在程序中先前获取它,从而避免需要从数据库中重新获取它。我已经将内存中的业务对象,所以为什么不使用那个呢?因此,我需要内存中可用对象的列表可以搜索(快速)。

提供的代码使用“TObject数组”来存储收集的对象,一旦达到一定数量,这对于搜索对象列表不会非常有效。我必须将其更改为TObjectList或某种二进制可搜索树。这里最好的选择是什么?我已经在http://www.ibrtses.com/delphi/binarytree.html找到了一些有用的代码(我认为)。 JCL在二叉树上没有东西吗?

如何处理该树中的“业务对象”和“业务对象列表”?作为列表一部分的业务对象是否会在树中引用两次?

关于处理对象:我还想为该业务对象设置某种TTL(生存时间),在一定时间后强制重新获取。 如果引用计数器降到0,我仍然希望将对象保留一段时间,如果程序仍然需要它在TTL内。这意味着我需要排序一些线程监视器来循环对象列表(或树)来监视要删除的对象。

我还遇到了Boehm垃圾收集器DLL(http://codecentral.embarcadero.com/Download.aspx?id=21646)。

简而言之,将我的“对象管理器”建立在EDN文章中提供的源代码上是否明智?我想要将对象存储在哪种列表中?我该如何处理列表中的对象列表?我是否应该将我的对象保留在内存中一段时间​​并通过线程监视器进行处理?

我的推理是否正确?在开始编码之前有任何建议,想法或评论吗?也许一些新想法可以融入我的代码中?

顺便说一下,一旦有些聪明的头脑想出来,我很乐意分享结果,让别人受益。

日Thnx。

5 个答案:

答案 0 :(得分:3)

如果您使用Interfaces进行引用计数,然后将它们粘贴到某种类型的集合中,那么您将始终引用它们。如果您的目标是“垃圾收集”,那么您只需要一个或另一个,但如果有必要,您当然可以使用它们。

您真正想要的是业务对象缓存。为此,您需要使用新的通用 TDictionary 集合之一。您可能想要做的是拥有TDictionary的TDictionary集合,每个对象类型都有一个TDictionary。您可以在枚举上键入主TDictionary,或者甚至可以在对象本身的类型上键入(我没有尝试过,但它可能有效。)如果您使用GUID作为唯一标识符,那么您可以将它们全部放入一个TDictionary。

使用接口实现每个业务对象。您不需要使用智能指针,因为您正在设计业务对象并可以从TInterfacedObject下载它们。然后只通过它的界面引用它,所以它可以被引用计数。

如果要使缓存过期,则需要在对象上设置某种时间戳,每次从缓存中检索对象时都会更新这些时间戳。然后,当缓存超过某个特定大小时,您可以修剪比某个时间戳更旧的所有内容。当然,这需要遍历整个缓存来执行此操作。

由于您正在组合接口和集合,因此如果您有一个对象的引用(通过其接口),并且在缓存清理期间它被修剪,那么该对象将保持活动状态,直到引用消失为止。这为您提供了额外的安全保障。当然,如果您仍在使用引用,那么这意味着您长时间保留引用而不从缓存中检索它。在这种情况下,您可能还希望在读取或写入属性时更新时间戳。 。 。其中很大程度上取决于您将如何使用业务对象。

就重新获取而言,如果从缓存中检索到的对象早于重新获取限制,则只希望这样做。这样,如果在再次使用它之前进行修剪,则不会浪费数据库之旅。

您可能会考虑在每个表中都有最后修改时间。然后,当您从缓存中获取对象时,您只需根据数据库中的时间检查内存中的时间。如果对象自上次检索后已更改,则可以更新它。

我会将更新对象限制为从缓存中检索它们的时间。这样,您在使用对象时就不太可能修改对象。如果你正在读取一个对象的数据,而它的变化会产生一些非常奇怪的行为。根据您的使用方式,有几种方法可以解决这个问题。

关于使用接口的警告,您不应该同时具有对同一对象的对象和接口引用。这样做会导致引用计数出现问题,并导致在仍有对象引用时释放对象。

我相信会有一些反馈,所以选择听起来像是最好的解决方案。 。 。

当然,现在我已经写了所有这些,我建议你看一下那里的某种业务对象框架。 RemObjects有一个很好的框架,我相信还有其他框架。

答案 1 :(得分:1)

您可能希望从查看智能指针开始。对于D2009,巴里凯利有implimentation

对于BI对象,我会使用guid作为关键字段,或者使用整个数据库中唯一的整数。当您将对象加载到内存中时,可以使用guid作为键并将容器对象作为值将它们存储在字典中。

容器对象包含bi对象,ttl等。

在加载对象之前,请检查字典以查看它是否已存在。如果它在那里,检查ttl并使用它,或重新加载并存储它。

答案 2 :(得分:1)

从更高层次的角度来看,我推荐两本书:“企业应用程序架构的模式”,作者:Martin Fowler和Eric Evans关于领域驱动设计的书,“领域驱动设计:解决软件核心中的复杂性” (http://dddcommunity.org/books#DDD)。 Martin Fowler解释了业务应用程序的所有对象管理模式,包括对象存储库和不同的对象/数据库映射策略。埃里克埃文斯的书“......提供了一个制定设计决策的广泛框架......”。

有一些(开源)O / R映射器库用于Delphi和活动社区,也许他们的源代码也可以提供一些技术指导。

答案 3 :(得分:1)

对于容器对象中非常快速的“按名称”查找,我建议您不要查看树,而应查看哈希表。 Delphi的EZ-DSL(Easy Data Structures)库包含EHash.pas单元,我将其用于散列容器。如果您对此感兴趣,我会转发给您。

我倾向于认为“生命周期”导向的“容器”会删除他们关闭时拥有的所有对象。

我还认为你可以考虑通过拥有一个“FLastUsed:Cardinal”数据字段来使对象本身算作“有用”。您可以分配FLastUsed:= GetTickCount,然后让系统基本上遵守您设置的限制,最大内存或要主动使用的实例以及在“降级”之前对象的年龄(在X毫秒内根本不使用)到2级,3级等。

我认为对于Business Objects来说,你有内存成本(当它真的只是一个缓存时保持它),以及一致性(在你可以摧毁我之前刷新我对数据库的更改)约束使得传统对于整个业务对象生命周期管理问题,“垃圾收集”的想法是必要的,但还不够。

答案 4 :(得分:0)

您正在寻找一种方法来构建一个可以存储业务对象的容器,并且能够在运行时找到已经实例化的容器吗?

也许你可以看一下http://www.danieleteti.it/?p=199(控制反转和依赖注入模式。)