问题标签 [reference-cycle]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
1 回答
972 浏览

objective-c - 块中的@synchronized(self) 是否会导致保留周期?

假设我想@synchronized(self)在一个街区内做。我想这会导致一个保留周期,所以通常我们会像这样重写它:

我的问题是,当您以@synchronized这种方式使用指令时,它是否等同于@synchronized(self)

0 投票
1 回答
776 浏览

methods - 如何从方法的闭包中删除强引用循环?

这里我有一些关闭强引用循环的例子。如果我将一个闭包分配给一个存储的属性,我可以使用一个闭包捕获列表来使捕获的引用无主/弱。但是,如果我将方法分配给存储的属性闭包或将方法分配给外部范围内的闭包,我将无法使用捕获列表。

在最后两种情况下,我该怎么做才能删除参考循环?

使用仅闭包的捕获列表创建和避免强引用循环的示例

使用方法闭包创建强引用循环的示例

通过从外部方法设置闭包来创建强引用循环的示例

输出

测试“强烈引用自我的闭包”:

正在取消初始化具有属性“ClosureClass 的默认值”的对象

测试“使用方法实习生设置闭包”:

测试“使用外部方法设置闭包”:

0 投票
2 回答
1008 浏览

objective-c - 将弱指针分配给强指针会复制对象吗?

避免在块内捕获自我的常见模式是在块外创建一个弱自我,并使用它在块内创建一个“局部强”版本的自我(内在自我)。

执行该行时会发生什么innserSelf creation?发送方法时是否是selfinnerSelf副本methodThatTakesCompletionBlock:someOtherObject

这个问题只关注执行 innserSelf 行时会发生什么。我已经看到对块内的弱引用的强引用,它是相关的,但没有解决这一点。

0 投票
2 回答
825 浏览

python - 当观察者[应该]被销毁时如何在python中正确实现观察者

我在 python 中实现了一个观察者可观察的模式:

这是 Observable 类:

这是一个观察者:

该代码按预期工作。

但我需要将Observer其销毁(即,当它未被引用时,它应该从Observable对象中的观察者列表中删除自己)。

问题是,使用此代码,如果在某个对象的观察者列表中,Observer.__del__则永远不会被调用。ObserverObservable

请注意,我不一定要Observer显式销毁它,它也会因为变量赋值而未被引用,因此removeObserver()在销毁之前显式调用是不可行的。

如果我注释掉self.foo.addObserver(self),那么就没有额外的引用Observer,并且调用del它会调用Observer.__del__.

这个场景的测试用例是:

它有两个结果:

  • 如果self.foo.addObserver(self)没有被注释掉,它会打印foo changed from 23 to 44foo changed from 44 to 1
  • 如果self.foo.addObserver(self)被注释掉,它会打印Observer.__del__ called
0 投票
2 回答
355 浏览

swift - 为什么添加闭包捕获列表会阻止我的实例被释放?

然后控制台会输出:

可以看出调用了“deinit”函数。所以不会形成强参考循环。但是如果我在闭包中添加一个捕获列表:

控制台将输出:

并且没有调用“deinit”函数。所以对象和引用形成了一个强引用循环。

是什么原因?这两个条件有什么区别?

0 投票
1 回答
589 浏览

swift - 对 HTTP 请求使用 [weak self]

我有一个关于是否需要在闭包和 HTTP 请求中使用 [weak self] 的问题。

例如,我们有一个 HTTP 请求,它在完成时触发关闭:

我的问题是:我是否需要在这里使用弱引用?首先,在移动到另一个页面后,我不想丢失来自 api 调用的响应。除此之外,我不想创建一个内存泄漏的保留周期?

在这种情况下真的需要使用[弱自我]吗?

0 投票
0 回答
43 浏览

node.js - nodejs - forEach 是否创建参考循环?

我是新手NodeJS,我的背景是Swift

面对时forEach,我想知道它是否会创建一个参考循环?

Swift,上面的代码将创建一个引用循环,因为闭包已经引用了一个函数self,即doSomething. 这也是NodeJS的情况吗?

问候,

0 投票
1 回答
36 浏览

objective-c - 回调强引用循环

以下是否创建了一个强大的参考循环?我有一种感觉,这是因为我self在回调中引用。

0 投票
0 回答
79 浏览

python - 使用检查模块时的参考周期

文档

注意保留对框架对象的引用,如这些函数返回的框架记录的第一个元素中所示,可能会导致您的程序创建引用循环。一旦创建了引用循环,即使启用了 Python 的可选循环检测器,可以从形成循环的对象访问的所有对象的生命周期也会变得更长。如果必须创建这样的循环,重要的是确保它们被明确地破坏以避免对象的延迟销毁和发生的内存消耗增加。

尽管循环检测器会捕获这些,但可以通过删除finally子句中的循环来确定帧(和局部变量)的破坏。如果在编译 Python 或使用gc.disable(). 例如:

如果您想保留框架(例如稍后打印回溯),您还可以使用该frame.clear()方法打破引用循环。

据说这意味着有两件事相互引用。它们到底是什么?

您能否更准确地解释在什么条件下创建参考循环?当我inspect.currentframe()没有del frame?也一样inspect.stack()吗?还有其他方法/情况吗?

0 投票
2 回答
111 浏览

java - 是否可以从其终结器跟踪对象,以检测不同对象的终结器对对象的意外复活?

Java 中方法的众多问题finalize之一是“对象复活”问题(在此问题中解释):如果一个对象已完成,并且它保存了全局可访问的某个位置的副本this,则对该对象的引用“转义”并且你结束有一个最终确定的但有生命的对象(不会再次最终确定,否则会出现问题)。

为了避免创建复活的对象,通常的建议(例如,在这个答案中看到)是创建对象的新实例,而不是保存对象本身;这通常可以通过将所有对象的字段复制到一个新对象中来完成。在大多数情况下,这实现了允许原始对象被释放而不是复活的目标。

但是,Java 垃圾收集器支持引用循环的垃圾收集;这意味着一个对象可以在(直接或间接)包含对自身的引用时完成,并且两个对象可以在(直接或间接)包含对彼此的引用时完成。在这种情况下,“将所有字段复制到一个新对象”建议实际上并不能解决问题。虽然我们在终结器完成运行后丢弃this引用,但部分终结的对象将通过来自字段的引用复活。因此,无论如何我们最终都会使对象复活。

在对象间接持有对自身的引用的情况下,可以递归地查看对象的所有字段,直到找到自引用(在这种情况下,我们可以将其替换为对新对象的引用建造),从而防止复活。这样就解决了这种情况下的问题。

然而,如果两个对象持有对彼此的引用(因此两者同时被释放),并且我们正在为每个对象创建一个新实例,那么每个新对象都将持有对旧的最终对象的引用(而不是作为替代构造的新对象)。这显然是一种不良状态,所以我一直在研究的一件事是尝试使用与单对象情况相同的解决方案:递归扫描(活的、新构造的)对象的字段以查找最终对象,并用相应的替换对象替换它们。

问题是:当我这样做时,如何识别最终/复活的对象?显而易见的方法是在终结器中以某种方式记录最终对象的身份,然后将我们在递归扫描期间找到的所有对象与最终对象列表进行比较。问题是,似乎没有有效的方法来记录相关对象的身份:

  • 常规(强)引用将使对象保持活动状态,有效地自动复活它,并且不提供任何方法来确定对象实际上没有被引用。这将解决识别复活对象的问题,但也有其自身的问题:虽然复活的对象将永远不会被使用,除了它们的身份之外,没有任何方法可以释放它们(例如,你不能使用 aPhantomReference来检测对象现在真的死了,就像在 Java 中通常那样,因为对象现在是强可达的,因此幻像引用永远不会清除)。所以这实际上意味着有问题的对象永远保持分配状态,从而导致内存泄漏。
  • 使用弱引用是我的第一个想法,但有一个问题是,在我们构造WeakReference对象时,被引用的对象实际上不是强、软、弱可达的。因此,一旦我们存储了WeakReference可强到达的任何位置(以防止WeakReference自身被释放),WeakReference的目标就变得弱可到达并且引用自动清除。所以我们不能以这种方式存储任何信息。
  • 使用幻像引用的问题是,无法将幻像引用与对象进行比较以查看该引用是否引用了该对象。(也许应该有 - 不像get(),它可以复活一个对象,这个操作从来没有任何危险,因为我们显然有一个对该对象的引用 - 但它在 Java API 中不存在。同样,.equals()PhantomReference对象上是==,不是值相等,因此您不能使用它来确定两个幻像引用是否引用同一事物。)
  • 使用System.identityHashCode()记录对应于对象身份的数字几乎可以工作 - 对象的释放不会改变记录的数字,数字不会阻止对象的释放,并且复活对象会使值保持不变 - 但不幸的是,作为一个hashCode,它容易发生碰撞,因此可能会出现误报,其中一个对象似乎复活了,但实际上并没有。
  • 最后一种可能性是修改对象本身以将其标记为已完成(并跟踪其替换的位置),这意味着在一个强可达对象上观察此标记将显示它是一个复活的对象,但这需要添加一个额外的字段来引用循环中可能涉及的任何对象。

总而言之,我的根本问题是“给定一个当前正在完成的对象,安全地创建它的副本,而不会意外地复活可能在该过程中它的引用循环中的任何对象”。我一直在尝试使用的方法是“当一个可能参与循环的对象最终确定时,跟踪该对象的身份,以便随后可以用它的副本替换它,如果它证明可以从另一个最终确定的对象”;但上述五种方法似乎都不令人满意。

是否有其他方法可以跟踪最终对象,以便在意外重定向时可以识别它们?对于原始问题是否有完全不同的解决方案,即在对象完成过程中安全地复制对象?