【问题标题】:How to start building a searchable garbage collector in Delphi (2009-2010)如何开始在 Delphi 中构建可搜索的垃圾收集器(2009-2010)
【发布时间】:2010-01-26 06:27:03
【问题描述】:

我正在寻找一种方法来控制我在用 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 文章中提供的源代码是否明智?我想将我的对象存储在什么样的列表中?我应该如何处理列表中的对象列表?我是否仍应将我的对象在内存中保留一段时间并由线程监视器处理它?

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

顺便说一句,我很乐意分享结果,让其他人受益,一旦一些聪明的头脑给出了想法。

谢谢。

【问题讨论】:

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


    【解决方案1】:

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

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

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

    如果您想使缓存过期,那么您需要在对象上设置某种时间戳,每次从缓存中检索对象时都会更新该时间戳。然后,当缓存超过某个特定大小时,您可以修剪比某个时间戳更早的所有内容。当然,这需要遍历整个缓存才能做到这一点。

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

    就重新获取而言,您只想在从缓存中检索到比重新获取限制更早的对象时执行此操作。这样,如果它在您再次使用它之前被修剪,您就不会浪费数据库行程。

    您可能会考虑在每个表中只设置一个最后修改时间。然后,当您从缓存中获取对象时,您只需检查内存中的时间与数据库中的时间。如果对象自上次检索后已更改,您可以对其进行更新。

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

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

    我相信会有一些反馈,所以请选择最适合您的解决方案。 . . .

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

    【讨论】:

    • 我很好奇是否有人使用过 RemObjects 框架,以及他们是否有任何主观的“它很好”或“它很糟糕”的 cmets 可以分享。
    • @Warren P,对我来说听起来像是一个单独的问题。
    • Tnx Jim 为您的回复。我查看了 TDictionary 类。帮助文件指出:添加或删除键值对并查找键是有效的,接近 O(1),因为键是散列的。这看起来很有希望。还有一个 TObjectDictionary,一旦从列表中删除,它会自动释放对象。将其与接口对象(使用引用计数器)进行比较,我想我会选择 TDictionary 对象。我没有 RemObjects 可供我使用,但阅读了一些非常积极的评论,所以也许其他人可以在这方面进一步补充我......
    【解决方案2】:

    您可能希望从查看智能指针开始。 Barry kelly 有一个 implimentation 代表 D2009。

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

    容器对象包含bi对象、ttl等

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

    【讨论】:

      【解决方案3】:

      为了在您的容器对象中快速“按名称”查找,我建议您不要查看树,而是查看哈希表。 Delphi 的 EZ-DSL(简单数据结构)库包括 EHash.pas 单元,我将其用于我的散列容器。如果您对此感兴趣,我会转发给您。

      我倾向于想到面向“生命周期”的“容器”,它们在关闭时会删除它们拥有的所有对象。

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

      我在想,对于 Business Objects,你有一个内存成本(当它实际上可能只是一个缓存时保留它)和一个一致性(在你破坏我之前刷新我对数据库的更改)约束,这使得传统对于业务对象生命周期管理的整个问题,“垃圾收集”想法是必要的,但还不够。

      【讨论】:

        【解决方案4】:

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

        已经有一些(开源)Delphi 的 O/R 映射器库具有活跃的社区,也许它们的源代码也可以提供一些技术指南。

        【讨论】:

        • afaik tiOPF 支持基于接口的对象管理,这不是解决垃圾回收问题吗?
        • 是的,但它在创建新业务对象时不处理搜索部分。
        【解决方案5】:

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-12-30
          • 1970-01-01
          相关资源
          最近更新 更多