4

情况

在开发过程中,我实现了称为对象池模式的设计模式。基本上这意味着我们的类有一个静态的公共方法和一个静态保护的属性。该属性携带所有实例,如果提供了某个对象键,则可以通过静态公共方法检索这些实例。我使用一个调用方法get_instance将实例检索到本地引用变量中,然后在其上调用其他方法。在我们的例子中,一个包装函数模块调用get_instance,然后在该实例上调用一些方法。在特定情况下,某个实例的生命周期结束。因此,它必须从对象池中删除。到目前为止,我在实例方法中执行此操作,其中对象从池(表)中删除自身。

假设

功能模块中的外部引用应该已经失效,因为它确实引用了一个不存在的对象。如果我假设正确,垃圾收集器现在应该携带这个孤立的引用。(通常情况相反:一个未引用的对象通常被 GC 杀死。)在这种情况下,我仍然假设我的功能模块中的本地引用也应该被收集。因为它所引用的对象已从对象池中删除。尽管如此,直到现在,我仍然调用Free lr_myreference. 一位同事说,最好实现一个静态公共方法,它不会对引用起作用,而只是在调用Free lr_myreference.

问题

一般来说,我在想:谁负责从池中删除对象?引用表中条目的其他本地引用(“原始引用”)呢?

4

2 回答 2

4

我经常使用您描述的相同模式,最好将一些哈希表保存为工厂/管理器/池类的静态属性。

就个人而言,我尽量避免需要明确完成的对象。根据我的经验,随着应用程序变得越来越复杂,总会有人倾向于忘记最终确定。反过来,这可能会导致许多众所周知的难以调试的不良副作用。我尝试遵循这样一个基本假设,即垃圾收集器最清楚何时删除一个对象,并且一旦对象消失,那就是全部了。只要任何人(一个函数组,另一个类,没关系)保持对一个对象的引用,它仍然在使用中并且不会被 gc'ed。除了需要频繁显式解构对象实例的控制框架之外,这种方法效果很好。

这种方法的明显缺点是对象池将趋于增长,除非实施得当。我的实例哈希表不包含对实例的硬引用;相反,我使用它CL_ABAP_WEAK_REFERENCE来跟踪托管对象。这允许垃圾收集器删除所有未在其他地方使用的托管实例。当然,这也意味着您需要通过其他直接引用来跟踪您仍然需要的实例(例如使用封装ENQUEUE/DEQUEUE调用并同时用作锁定令牌的锁定对象 - 无论该对象的当前所有者是谁也负责再次释放锁)。

警告:在广泛使用弱引用时,必须避免一个相当常见的结构错误。我前段时间写了一篇SCN 文章,其中包含一个(反)示例。底线:如果通过弱引用引用管理对象(在您的示例中,池类),请确保托管实例具有对管理器的硬引用 - 否则您可能会意外地得到几组托管实例代表同一件事。

于 2015-12-08T17:58:36.977 回答
2

从本质上讲,您正在将对象的所有权暂时从池中转移(或至少借出)给调用者get_instance,因此池无法杀死该对象或将其从池中删除,直到它知道新所有者已完成使用该对象。如果是这样,则当前所有者可能会留下无效对象。

因此,为了让池正确地完成它的工作,您需要将对象返回到池中(或告诉它您已经使用完它),以便池可以知道哪些对象当前未使用并可以安全地销毁它们。

我会有一个return_instance可以做到这一点的对象。

如果您有多个客户端调用get_instance并且您正在给他们相同的实例,那么您需要通过引用计数进行跟踪,否则您可以将引用保存在两个列表中,一个用于可用对象,另一个用于当前借出的对象,并且只是在调用get_instance和时在列表之间切换。return_instance

客户不应该负责销毁对象,否则拥有一个池有什么意义?换个工厂就好了...

前阵子问了一个稍微相关的问题,影响了我的思考

于 2015-12-08T16:44:00.217 回答