问题标签 [reference-counting]

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 投票
3 回答
1442 浏览

c++ - 如何更好地为不可创建的 COM 对象初始化引用计数器?

我有一个带有返回对象的方法的 COM 接口:

关键是调用ICreatorInterface::CreateObject()是检索对象实现IObjectToCreate接口的唯一方法。

在 C++ 中,我可以这样做:

或者这样

不同之处在于引用计数器是如何初始化的,以及在QueryInterface()失败时如何实现对象删除。因为我完全控制了两者CCreatorInterfaceImplCObjectToCreateImpl所以我可以选择任何一种方式。

IMO 第一个变体更清晰——所有引用计数的东西都在一段代码中。我监督了什么?为什么第二种方法会更好?以上哪个更好,为什么?

0 投票
1 回答
305 浏览

excel - 计算事件的频率

我有一串股票价格数据,我希望能够计算价格上涨或下跌持续了多少天。因此,例如,从数据中我有一个使用过的“if”函数来确定一天是向上还是向下:“U”表示向上的一天,“D”表示向下的一天。假设字符串看起来像这样:

UUUDDUDUDUDUUU

我想要一个公式来计算有 3 天上涨,2 天下跌,1 上涨,1 下跌等……然后我将能够建立一个价格向一个方向移动持续多长时间的概况。 ..我想在直方图或图表中显示结果。

有谁知道我可以使用什么公式或函数来获得我想要的结果?

感谢任何帮助。谢谢

0 投票
6 回答
405 浏览

c++ - 要获得引用计数,我是否必须将我的 API 与 shared_ptr 混为一谈?

我最近遇到了以下内存错误,在这里很容易发现,但在更复杂的代码中更难检测到:

错误是Bar立即超出范围,被销毁然后在foo->test(). 一种解决方案是Bar在堆上创建,使用Bar* bar = new Bar(). 但是,我不喜欢这样做,因为我必须将Bar* bar指针保持在顶层,这样我才能delete在最后访问它,即使Bar是特定于该特定代码块的东西if(whatever){}

另一个解决方案是boost::shared_ptr<Bar>,但我不能只写这个:

因为shared_ptr也立即超出范围,破坏了包含的对象。

所以简而言之,为了摆脱这个问题,我必须在shared_ptr任何地方使用,inFoo作为成员变量,inFoo的构造函数等。为了消除这些问题,我所有的 API 等都必须使用shared_ptr,这很友好丑陋的。但是,这样做是正确的吗?到目前为止,我有时使用它来创建引用计数对象,但我的 API 保持干净shared_ptr。你如何处理这个问题,一旦你使用,shared_ptr你必须在任何地方使用它?

(另外,如果你使用这些引用计数的指针,你必须开始担心你是否真的想要shared_ptr或者更确切地说weak_ptr等等)

而且,我将使用什么来等效于Foo(const Bar& bar)Foo(const shared_ptr<const Bar> bar)?

当然,另一种选择是在自己的Bar对象和其他对象中添加引用计数,使用pimpl自己的计数器,但作为一般规则,这太乏味了。

0 投票
5 回答
1829 浏览

algorithm - 如何有效地调试共享内存中的引用计数问题?

假设您在共享内存中有一个引用计数对象。引用计数表示使用对象的进程数,进程负责通过原子指令递增和递减计数,所以引用计数本身也是在共享内存中的(可以是对象的字段,也可以是对象可能包含指向计数的指针,如果他们有助于解决这个问题,我愿意接受建议)。有时,一个进程会有一个错误,阻止它减少计数。您如何尽可能轻松地找出哪个进程没有减少计数?

我想到的一个解决方案是给每个进程一个 UID(也许是他们的 PID)。然后,当进程递减时,它们会将其 UID 推送到与引用计数一起存储的链表上(我选择了链表,因为您可以使用CAS原子地附加到头部)。当你想调试时,你有一个特殊的过程来查看仍然存在于共享内存中的对象的链表,并且无论哪个应用程序的 UID 不在列表中,都是那些尚未减少计数的应用程序的 UID。

此解决方案的缺点是它使用 O(N) 内存,其中 N 是进程数。如果使用共享内存区域的进程数量很大,并且您有大量对象,那么这很快就会变得非常昂贵。我怀疑可能有一个中途解决方案,使用部分固定大小的信息,您可以通过某种方式缩小可能进程的列表来帮助调试,即使您无法查明一个进程。或者,如果您可以检测到只有一个进程没有减少时哪个进程没有减少(即无法处理检测到 2 个或多个未能减少计数的进程),那可能仍然会有很大帮助。

(对于这个问题有更多的“人为”解决方案,比如确保所有应用程序使用同一个库来访问共享内存区域,但是如果共享区域被视为二进制接口并且并非所有进程都将是由你那是你无法控制的。此外,即使所有应用程序都使用同一个库,一个应用程序也可能在库之外有一个错误,以防止减少计数的方式破坏内存。是的,我使用的是一种不安全的语言,比如C/C++ ;)

编辑:在单进程情况下,您将拥有控制权,因此您可以使用RAII(在 C++ 中)。

0 投票
10 回答
5826 浏览

c# - 是否可以拦截(或知道)暴露给 COM 的 CLR 对象上的 COM 引用计数

我已经改写了这个问题。

当 .net 对象通过 COM iterop 暴露给 COM 客户端时,会创建一个 CCW(COM 可调用包装器),它位于 COM 客户端和托管 .net 对象之间。

在 COM 世界中,对象会计算其他对象对它的引用次数。当引用计数变为零时,对象将被删除/释放/收集。这意味着 COM 对象终止是确定性的(我们在 .net 中使用 Using/IDispose 进行确定性终止,对象终结器是非确定性的)。

每个 CCW 都是一个 COM 对象,它像任何其他 COM 对象一样被引用计数。当 CCW 死亡(引用计数归零)时,GC 将无法找到 CCW 包装的 CLR 对象,并且 CLR 对象有资格被收集。快乐的日子,世界一切都好。

我想做的是在 CCW 死亡时(即,当它的引用计数变为零时)捕获,并以某种方式向 CLR 对象发出信号(例如,通过在托管对象上调用 Dispose 方法)。

那么,是否有可能知道 CLR 类的COM 可调用包装器的引用计数何时变为零?
和/或
是否可以在.net 中为 CCW 提供我的 AddRef 和 ReleaseRef 实现?

如果不是,另一种方法是在 ATL 中实现这些 DLL(我不需要 ATL 的任何帮助,谢谢)。这不是火箭科学,但我不愿意这样做,因为我是唯一拥有任何现实世界 C++ 或任何 ATL 的内部开发人员。

背景
我正在.net 中重写一些旧的 VB6 ActiveX DLL(确切地说是 C#,但这更多是 .net/COM 互操作问题而不是 C# 问题)。一些旧的 VB6 对象依赖于引用计数来在对象终止时执行操作(参见上面对引用计数的解释)。这些 DLL 不包含重要的业务逻辑,它们是我们提供给使用 VBScript 与我们集成的客户端的实用程序和辅助函数。

我不想做什么

  • 引用计数 .net 对象而不是使用垃圾收集器。我对 GC 很满意,我的问题不在于 GC。
  • 使用对象终结器。终结器是非确定性的,在这种情况下,我需要确定性终止(如 .net 中的 Using/IDispose 习惯用法)
  • 在非托管 C++ 中实现 IUnknown
    如果我必须走 C++ 路线,我将使用 ATL,谢谢。
  • 使用 Vb6 解决此问题,或重新使用 VB6 对象。这个练习的重点是消除我们对 Vb6 的构建依赖。

谢谢
BW

接受的答案
感谢Steve Steiner,他提出了唯一(可能可行的)基于 .net 的答案,以及Earwicker,他提出了一个非常简单的 ATL 解决方案。

然而,接受的答案是Bigtoe,他建议将 .net 对象包装在 VbScript 对象中(我认为这不是诚实的),有效地为 VbScript 问题提供了一个简单的 VbScript 解决方案。

谢谢大家。

0 投票
1 回答
115 浏览

cocoa - 这是 Cocoa 引用计数的正确总结吗?

以下是我对它的理解:

保留对象(引用计数器递增):

  1. 何时调用initfrom 。NSObject
  2. 什么时候retain调用。

释放对象(引用计数器递减):

  1. 什么时候release调用。
  2. 当包含对象的自动释放池被耗尽时

澄清一下,自动释放不会保留,而只是将对象放入自动释放池堆栈的最顶层池中。

0 投票
2 回答
10584 浏览

binary-tree - 处理 AVL 树中的重复键

我想让我的avl-tree支持重复键,但是具有重复项的默认行为存在问题,binary search tree即旋转可以使具有相同键的节点位于父级的左侧和右侧。

例如,当添加三个节点都带有键 A 时,会导致树进行旋转,如下所示:

因此,使用该键获取所有条目将是一个问题……并且双向搜索并不好。

我想到的解决方案是让每个节点存储一个重复的数组,所以当添加一个已经存在的新项目时,只需向数组中添加一个新项目,使用键删除项目将删除整个节点,同时查找所有项目with key 将返回该数组。

是否有任何其他方法来处理重复?

插入项需要一个键和一个值..所以我需要存储值以便通过 findAll 使用某些键方法返回它们。

0 投票
3 回答
484 浏览

c++ - Can you force a crash if a write occurs to a given memory location with finer than page granularity?

I'm writing a program that for performance reasons uses shared memory (sockets and pipes as alternatives have been evaluated, and they are not fast enough for my task, generally speaking any IPC method that involves copies is too slow). In the shared memory region I am writing many structs of a fixed size. There is one program responsible for writing the structs into shared memory, and many clients that read from it. However, there is one member of each struct that clients need to write to (a reference count, which they will update atomically). All of the other members should be read only to the clients.

Because clients need to change that one member, they can't map the shared memory region as read only. But they shouldn't be tinkering with the other members either, and since these programs are written in C++, memory corruption is possible. Ideally, it should be as difficult as possible for one client to crash another. I'm only worried about buggy clients, not malicious ones, so imperfect solutions are allowed.

I can try to stop clients from overwriting by declaring the members in the header they use as const, but that won't prevent memory corruption (buffer overflows, bad casts, etc.) from overwriting. I can insert canaries, but then I have to constantly pay the cost of checking them.

Instead of storing the reference count member directly, I could store a pointer to the actual data in a separate mapped write only page, while keeping the structs in read only mapped pages. This will work, the OS will force my application to crash if I try to write to the pointed to data, but indirect storage can be undesirable when trying to write lock free algorithms, because needing to follow another level of indirection can change whether something can be done atomically.

Is there any way to mark smaller areas of memory such that writing them will cause your app to blow up? Some platforms have hardware watchpoints, and maybe I could activate one of those with inline assembly, but I'd be limited to only 4 at a time on 32-bit x86 and each one could only cover part of the struct because they're limited to 4 bytes. It'd also make my program painful to debug ;)

Edit: I found this rather eye popping paper, but unfortunately it requires using ECC memory and a modified Linux kernel.

0 投票
3 回答
361 浏览

c++ - 通过组合实现引用计数可以吗?

最常见的可重用引用计数对象使用私有继承来实现重用。我不是私有继承的忠实拥护者,我很好奇这是否是一种可以接受的处理方式:

或者我没有看到这个有微妙的问题?

编辑
我不是超级关心这个特定的实现(它可能有错误——在生产代码中使用类似的东西之前,我将花一些时间查看 shared_ptr 的内部)——我只是担心一般情况下可重用引用计数好东西似乎总是使用继承而不是组合来实现,这是有一个特定原因的。

0 投票
2 回答
2236 浏览

python - 处理 C 代码时是否有任何 Python 引用计数/垃圾收集陷阱?

只是为了它,我决定创建一个与 libpython 的 Scheme 绑定,以便您可以将 Python 嵌入到 Scheme 程序中。我已经能够调用 Python 的 C API,但我还没有真正考虑过内存管理。

mzscheme 的 FFI 的工作方式是我可以调用一个函数,如果该函数返回一个指向 a 的指针PyObject,那么我可以让它自动增加引用计数。然后,我可以注册一个终结器,它会在 Scheme 对象被垃圾回收时减少引用计数。我查看了有关引用计数的文档,乍一看并没有发现任何问题(尽管在某些情况下它可能不是最佳的)。我有什么遗漏吗?

另外,我在制作循环垃圾收集器文档的正面或反面时遇到了麻烦。在这里我需要记住什么?特别是,我如何让 Python 知道我引用了某些东西,以便在我仍在使用它时它不会收集它?