知道什么引用了对象
我有一个实现引用计数机制的对象。如果对其的引用数量变为零,则删除该对象。
我发现我的对象永远不会被删除,即使我用完它也是如此。这会导致内存过度使用。我所拥有的只是对该对象的引用数量,我想知道引用它的位置,以便我可以编写适当的清理代码。
有什么方法可以完成此任务,而无需在源文件中进行 grep 操作? (那会非常麻烦。)
I have an object which implements reference counting mechanism. If the number of references to it becomes zero, the object is deleted.
I found that my object is never deleted, even when I am done with it. This is leading to memory overuse. All I have is the number of references to the object and I want to know the places which reference it so that I can write appropriate cleanup code.
Is there some way to accomplish this without having to grep in the source files? (That would be very cumbersome.)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
在 C++ 中正确完成引用计数(refcounting)的很大一部分是使用 资源分配就是初始化,因此意外泄漏引用要困难得多。然而,这并不能通过重新计数解决所有问题。
也就是说,您可以在引用计数中实现调试功能,以跟踪保存引用的内容。然后,您可以在必要时分析此信息,并将其从发布版本中删除。 (使用与 DEBUG 宏的使用方式类似的配置宏。)
具体如何实现它取决于您的所有要求,但有两种主要方法可以实现此目的(简要概述差异)
基本问题,了解什么引用给定的对象,通常很难解决,并且需要一些工作。比较:您能告诉我知道您的邮政地址或电话号码的每个人和企业吗?
A huge part of getting reference counting (refcounting) done correctly in C++ is to use Resource Allocation Is Initialization so it's much harder to accidentally leak references. However, this doesn't solve everything with refcounts.
That said, you can implement a debug feature in your refcounting which tracks what is holding references. You can then analyze this information when necessary, and remove it from release builds. (Use a configuration macro similar in purpose to how DEBUG macros are used.)
Exactly how you should implement it is going to depend on all your requirements, but there are two main ways to do this (with a brief overview of differences):
The basic problem, of knowing what is referencing a given object, is hard to solve in general, and will require some work. Compare: can you tell me every person and business that knows your postal address or phone number?
引用计数的一个已知弱点是,当存在循环引用时,即(在最简单的情况下)当一个对象引用另一个对象,而另一个对象又引用前一个对象时,它不起作用。这听起来似乎不是问题,但在诸如具有对父节点的反向引用的二叉树之类的数据结构中,就是这样。
如果您没有在引用的(未释放的)对象中明确提供“反向”引用列表,我看不到一种方法来找出谁在引用它。
在以下建议中,我假设您不想修改源代码,或者如果是的话,也只是修改一点点。
您当然可以遍历整个堆/自由存储并搜索未释放对象的内存地址,但如果它的地址出现,则不能保证它实际上是内存地址引用;它也可以是任何随机浮点数或其他任何数字。但是,如果找到的值位于应用程序为对象分配的内存块内,那么它确实是指向另一个对象的指针的可能性会有所提高。
对此方法的一个可能的改进是修改您使用的内存分配器——例如全局
operator new
——以便它保留所有分配的内存块及其大小的列表。 (在完整的实现中,operator delete
将删除已释放的内存块的列表条目。)现在,在程序末尾,您可以知道在哪里 em> 来搜索未释放对象的内存地址,因为您有一个程序实际使用的内存块列表。说实话,上述建议对我来说听起来不太可靠;但也许定义一个自定义的全局
operator new
和operator delete
来执行一些日志记录/跟踪会朝着解决您的问题的正确方向发展。One known weakness of reference counting is that it does not work when there are cyclic references, i.e. (in the simplest case) when one object has a reference to another object which in turn has a reference to the former object. This sounds like a non-issue, but in data structures such as binary trees with back-references to parent nodes, there you are.
If you don't explicitly provide for a list of "reverse" references in the referenced (un-freed) object, I don't see a way to figure out who is referencing it.
In the following suggestions, I assume that you don't want to modify your source, or if so, just a little.
You could of course walk the whole heap / freestore and search for the memory address of your un-freed object, but if its address turns up, it's not guaranteed to actually be a memory address reference; it could just as well be any random floating point number, of anything else. However, if the found value lies inside a block a memory that your application allocated for an object, chances improve a little that it's indeed a pointer to another object.
One possible improvement over this approach would be to modify the memory allocator you use -- e.g. your global
operator new
-- so that it keeps a list of all allocated memory blocks and their sizes. (In a complete implementation of this,operator delete
would have remove the list entry for the freed block of memory.) Now, at the end of your program, you have a clue where to search for the un-freed object's memory address, since you have a list of memory blocks that your program actually used.The above suggestions don't sound very reliable to me, to be honest; but maybe defining a custom global
operator new
andoperator delete
that does some logging / tracing goes in the right direction to solve your problem.我假设您有一些带有
addRef()
和release()
成员函数的类,并且当您需要增加和减少每个实例的引用计数时调用这些函数,并且导致问题的实例位于堆上并使用原始指针引用。最简单的修复可能是用boost::shared_ptr
替换所有指向受控对象的指针。这非常容易做到,并且应该使您能够省去自己的引用计数——您可以让我提到的那些函数什么都不做。代码中所需的主要更改是传递或返回指针的函数的签名。其他需要更改的地方是初始值设定项列表(如果将指针初始化为 null)和 if() 语句(如果将指针与 null 进行比较)。更改指针的声明后,编译器将找到所有此类位置。如果您不想使用shared_ptr - 也许您想保留类固有的引用计数 - 您可以制作自己的简单智能指针来处理您的类。然后用它来控制类对象的生命周期。例如,您不必使用原始指针完成指针分配并“手动”调用
addRef()
,而只需对包含addRef()< 的智能指针类进行分配即可/代码> 自动。
I am assuming you have some class with say
addRef()
andrelease()
member functions, and you call these when you need to increase and decrease the reference count on each instance, and that the instances that cause problems are on the heap and referred to with raw pointers. The simplest fix may be to replace all pointers to the controlled object withboost::shared_ptr
. This is surprisingly easy to do and should enable you to dispense with your own reference counting - you can just make those functions I mentioned do nothing. The main change required in your code is in the signatures of functions that pass or return your pointers. Other places to change are in initializer lists (if you initialize pointers to null) and if()-statements (if you compare pointers with null). The compiler will find all such places after you change the declarations of the pointers.If you do not want to use the
shared_ptr
- maybe you want to keep the reference count intrinsic to the class - you can craft your own simple smart pointer just to deal with your class. Then use it to control the lifetime of your class objects. So for example, instead of pointer assignment being done with raw pointers and you "manually" callingaddRef()
, you just do an assignment of your smart pointer class which includes theaddRef()
automatically.我认为不更改代码就不可能做某事。通过代码更改,您可以记住增加引用计数的对象的指针,然后查看剩下的指针并在调试器中检查它。如果可能 - 存储更详细的信息,例如对象名称。
I don't think it's possible to do something without code change. With code change you can for example remember the pointers of the objects which increase reference count, and then see what pointer is left and examine it in the debugger. If possible - store more verbose information, such as object name.
我根据自己的需要创建了一个。您可以将您的代码与此代码进行比较,看看缺少什么。它并不完美,但在大多数情况下应该有效。
http://sites.google.com/site/grayasm/autopointer
当我使用我这样做:
我从来没有这样做过:
然后开始用 ptr 来充实;这是不允许的。
此外,我仅使用 aptr 来引用该对象。
如果我错了,我现在有机会得到纠正。 :) 再见!
I have created one for my needs. You can compare your code with this one and see what's missing. It's not perfect but it should work in most of the cases.
http://sites.google.com/site/grayasm/autopointer
when I use it I do:
I never do it like this:
and later to start fulling around with ptr; That's not allowed.
Further I am using only aptr to refer to this object.
If I am wrong I have now the chance to get corrections. :) See ya!