我怎么知道谁拥有shared_ptr ?

时间:2021-08-17 06:16:58

I use boost::shared_ptr in my application in C++. The memory problem is really serious, and the application takes large amount of memory.

我在C ++的应用程序中使用boost :: shared_ptr。内存问题非常严重,应用程序占用大量内存。

However, because I put every newed object into a shared_ptr, when the application exits, no memory leaking can be detected.

但是,因为我将每个新建对象放入shared_ptr,当应用程序退出时,不会检测到内存泄漏。

There must be some thing like std::vector<shared_ptr<> > pool holding the resource. How can I know who holds the shared_ptr, when debugging?

必须有一些东西,如std :: vector >池保存资源。调试时如何知道谁拥有shared_ptr?

It is hard to review code line by line. Too much code...

很难逐行检查代码。代码太多......

Thanks very much!

非常感谢!

8 个解决方案

#1


You can't know, by only looking at a shared_ptr, where the "sibling pointers" are. You can test if one is unique() or get the use_count(), among other methods.

你只能通过查看“兄弟指针”所在的shared_ptr来了解。您可以测试一个是唯一的()还是获取use_count()以及其他方法。

#2


The popular widespread use of shared_ptr will almost inevitably cause unwanted and unseen memory occupation.

广泛使用的shared_ptr几乎不可避免地会导致不必要的和看不见的内存占用。

Cyclic references are a well known cause and some of them can be indirect and difficult to spot especially in complex code that is worked on by more than one programmer; a programmer may decide than one object needs a reference to another as a quick fix and doesn't have time to examine all the code to see if he is closing a cycle. This hazard is hugely underestimated.

循环引用是一个众所周知的原因,其中一些可能是间接的,很难发现,特别是在由多个程序员处理的复杂代码中;程序员可能决定一个对象需要引用另一个对象作为快速修复,并且没有时间检查所有代码以查看他是否正在关闭一个循环。这种危害被严重低估了。

Less well understood is the problem of unreleased references. If an object is shared out to many shared_ptrs then it will not be destroyed until every one of them is zeroed or goes out of scope. It is very easy to overlook one of these references and end up with objects lurking unseen in memory that you thought you had finished with.

不太了解的是未公开的参考文献的问题。如果一个对象被共享给许多shared_ptrs,那么在它们中的每一个被归零或超出范围之前它都不会被销毁。很容易忽略其中一个引用,并最终得到你认为已经完成的内存中看不见的对象。

Although strictly speaking these are not memory leaks (it will all be released before the program exits) they are just as harmful and harder to detect.

虽然严格来说这些不是内存泄漏(它将在程序退出之前全部释放),但它们同样有害且难以检测。

These problems are the consequences of expedient false declarations: 1. Declaring what you really want to be single ownership as shared_ptr. scoped_ptr would be correct but then any other reference to that object will have to be a raw pointer, which could be left dangling. 2. Declaring what you really want to be a passive observing reference as shared_ptr. weak_ptr would be correct but then you have the hassle of converting it to share_ptr every time you want to use it.

这些问题是权宜的虚假声明的结果:1。声明你真正希望成为shared_ptr的单一所有权。 scoped_ptr是正确的,但是对该对象的任何其他引用都必须是一个原始指针,可以留下悬空。 2.声明你真正想要成为被动观察引用的是shared_ptr。 weak_ptr是正确的,但是每次你想使用它时你都有把它转换成share_ptr的麻烦。

I suspect that your project is a fine example of the kind of trouble that this practice can get you into.

我怀疑你的项目是这种做法可以让你进入的那种麻烦的一个很好的例子。

If you have a memory intensive application you really need single ownership so that your design can explicitly control object lifetimes.

如果您有一个内存密集型应用程序,您确实需要单一所有权,以便您的设计可以显式控制对象生存期。

With single ownership opObject=NULL; will definitely delete the object and it will do it now.

单一所有权opObject = NULL;肯定会删除该对象,它现在就会这样做。

With shared ownership spObject=NULL; ........who knows?......

使用共享所有权spObject = NULL; ........谁知道?......

#3


One solution to dangling or circular smart pointer references we've done is customize the smart pointer class to add a debug-only bookkeeping function. Whenever a smartpointer adds a reference to an object, it takes a stack trace and puts it in a map whose each entry keeps track of

我们已经完成的悬空或循环智能指针引用的一种解决方案是自定义智能指针类以添加仅调试的簿记功能。每当一个智能指针添加一个对象的引用时,它会采用堆栈跟踪并将其放入一个地图中,每个条目都跟踪一个

  1. The address of the object being allocated (what the pointer points to)
  2. 被分配对象的地址(指针指向的对象)

  3. The addresses of each smartpointer object holding a reference to the object
  4. 每个智能指针对象的地址,包含对象的引用

  5. The corresponding stacktraces of when each smartpointer was constructed
  6. 构建每个智能指针时的相应堆栈跟踪

When a smartpointer goes out of scope, its entry in the map gets deleted. When the last smartpointer to an object gets destroyed, the pointee object gets its entry in the map removed.

当smartpointer超出范围时,它在地图中的条目将被删除。当对象的最后一个smartpointer被破坏时,指针对象将其地图中的条目删除。

Then we have a "track leaks" command with two functions: '[re]start leak tracking' (which clears the whole map and enabled tracking if its not already), and 'print open references', which shows all outstanding smartpointer references created since the 'start leak tracking' command was issued. Since you can see the stack traces of where those smart pointers came into being, you can easily know exactly who's keeping from your object being freed. It slows things down when its on, so we don't leave it on all the time.

然后我们有一个带有两个函数的“track leaks”命令:'[re]启动泄漏跟踪'(清除整个地图并启用跟踪,如果还没有),'print open references',显示所有未完成的智能指针引用自从'start leak tracking'命令发布以来。由于您可以看到这些智能指针所在的堆栈跟踪,因此您可以轻松地确切知道谁将保留您的对象。当它打开时它会减慢速度,所以我们不会一直保持这种状态。

It's a fair amount of work to implement, but definitely worth it if you've got a codebase where this happens a lot.

这是一项相当多的工作要实现,但如果你有一个代码库,这种情况发生了很多,那绝对是值得的。

#4


You may be experiencing a shared pointer memory leak via cycles. What happens is your shared objects may hold references to other shared objects which eventually lead back to the original. When this happens the cycle keeps all reference counts at 1 even though no one else can access the objects. The solution is weak pointers.

您可能正在通过循环遇到共享指针内存泄漏。发生的事情是您的共享对象可能包含对其他共享对象的引用,这些对象最终会返回原始对象。发生这种情况时,即使没有其他人可以访问对象,循环也会将所有引用计数保持为1。解决方案是弱指针。

#5


Try refactoring some of your code so that ownership is more explicitly expressed by the use of weak pointers instead of shared pointers in some places.

尝试重构一些代码,以便通过在某些地方使用弱指针而不是共享指针来更明确地表达所有权。

When looking at your class hierarchy it's possible to determine which class really should hold a shared pointer and which merely needs only the weak one, so you can avoid cycles if there are any and if the "real" owner object is destructed, "non-owner" objects should have already been gone. If it turns out that some objects lose pointers too early, you have to look into object destruction sequence in your app and fix it.

在查看类层次结构时,可以确定哪个类确实应该保存共享指针,哪些只需要弱指针,因此如果存在任何类,并且“真正的”所有者对象被破坏,则可以避免循环,“非所有者“对象应该已经消失了。如果事实证明某些对象过早丢失指针,则必须在应用程序中查看对象销毁序列并进行修复。

#6


You're obviously holding onto references to your objects within your application. This means that you are, on purpose, keeping things in memory. That means, you don't have a memory leak. A memory leak is when memory is allocated, and then you do not keep a reference to its address.

您显然在应用程序中持有对对象的引用。这意味着您有意将事物记忆在内。这意味着,您没有内存泄漏。内存泄漏是在分配内存时,然后您不保留对其地址的引用。

Basically, you need to look at your design and figure out why you are keeping so many objects and data in memory, and how can you minimize it.

基本上,您需要查看您的设计并找出为什么要在内存中保留如此多的对象和数据,以及如何将其最小化。

The one possibility that you have a pseudo-memory leak is that you are creating more objects than you think you are. Try putting breakpoints on all statements containing a 'new'. See if your application is constructing more objects than you thought it should, and then read through that code.

您有伪内存泄漏的一种可能性是您创建的对象比您想象的要多。尝试在包含'new'的所有语句上添加断点。查看您的应用程序是否构建了比您预期的更多的对象,然后阅读该代码。

The problem is really not so much a memory-leak as it is an issue of your application's design.

问题实际上不是内存泄漏,而是因为它是应用程序设计的问题。

#7


I was going to suggest using UMDH if you are on windows. It is a very powerful tool. Use it find allocations per transaction/time-period that you expect to be freed then find who is holding them.

如果你在Windows上,我打算建议使用UMDH。这是一个非常强大的工具。使用它查找您希望被释放的每个事务/时间段的分配,然后查找持有它们的人。

There is more information on this SO answer Find memory leaks caused by smart pointers

有关此SO答案的更多信息查找由智能指针引起的内存泄漏

#8


It is not possible to tell what objects own shared_ptr from within the program. If you are on Linux, one sure way to debug the memory leaks is the Valgrind tool -- while it won't directly answer your question, it will tell where the memory was allocated, which is usually sufficient for fixing the problem. I imagine Windows has comparable tools, but I am do not know which one is best.

无法从程序中分辨出哪些对象拥有shared_ptr。如果你在Linux上,调试内存泄漏的一种可靠方法是Valgrind工具 - 虽然它不会直接回答你的问题,但它会告诉你内存的分配位置,这通常足以解决问题。我想Windows有类似的工具,但我不知道哪一个是最好的。

#1


You can't know, by only looking at a shared_ptr, where the "sibling pointers" are. You can test if one is unique() or get the use_count(), among other methods.

你只能通过查看“兄弟指针”所在的shared_ptr来了解。您可以测试一个是唯一的()还是获取use_count()以及其他方法。

#2


The popular widespread use of shared_ptr will almost inevitably cause unwanted and unseen memory occupation.

广泛使用的shared_ptr几乎不可避免地会导致不必要的和看不见的内存占用。

Cyclic references are a well known cause and some of them can be indirect and difficult to spot especially in complex code that is worked on by more than one programmer; a programmer may decide than one object needs a reference to another as a quick fix and doesn't have time to examine all the code to see if he is closing a cycle. This hazard is hugely underestimated.

循环引用是一个众所周知的原因,其中一些可能是间接的,很难发现,特别是在由多个程序员处理的复杂代码中;程序员可能决定一个对象需要引用另一个对象作为快速修复,并且没有时间检查所有代码以查看他是否正在关闭一个循环。这种危害被严重低估了。

Less well understood is the problem of unreleased references. If an object is shared out to many shared_ptrs then it will not be destroyed until every one of them is zeroed or goes out of scope. It is very easy to overlook one of these references and end up with objects lurking unseen in memory that you thought you had finished with.

不太了解的是未公开的参考文献的问题。如果一个对象被共享给许多shared_ptrs,那么在它们中的每一个被归零或超出范围之前它都不会被销毁。很容易忽略其中一个引用,并最终得到你认为已经完成的内存中看不见的对象。

Although strictly speaking these are not memory leaks (it will all be released before the program exits) they are just as harmful and harder to detect.

虽然严格来说这些不是内存泄漏(它将在程序退出之前全部释放),但它们同样有害且难以检测。

These problems are the consequences of expedient false declarations: 1. Declaring what you really want to be single ownership as shared_ptr. scoped_ptr would be correct but then any other reference to that object will have to be a raw pointer, which could be left dangling. 2. Declaring what you really want to be a passive observing reference as shared_ptr. weak_ptr would be correct but then you have the hassle of converting it to share_ptr every time you want to use it.

这些问题是权宜的虚假声明的结果:1。声明你真正希望成为shared_ptr的单一所有权。 scoped_ptr是正确的,但是对该对象的任何其他引用都必须是一个原始指针,可以留下悬空。 2.声明你真正想要成为被动观察引用的是shared_ptr。 weak_ptr是正确的,但是每次你想使用它时你都有把它转换成share_ptr的麻烦。

I suspect that your project is a fine example of the kind of trouble that this practice can get you into.

我怀疑你的项目是这种做法可以让你进入的那种麻烦的一个很好的例子。

If you have a memory intensive application you really need single ownership so that your design can explicitly control object lifetimes.

如果您有一个内存密集型应用程序,您确实需要单一所有权,以便您的设计可以显式控制对象生存期。

With single ownership opObject=NULL; will definitely delete the object and it will do it now.

单一所有权opObject = NULL;肯定会删除该对象,它现在就会这样做。

With shared ownership spObject=NULL; ........who knows?......

使用共享所有权spObject = NULL; ........谁知道?......

#3


One solution to dangling or circular smart pointer references we've done is customize the smart pointer class to add a debug-only bookkeeping function. Whenever a smartpointer adds a reference to an object, it takes a stack trace and puts it in a map whose each entry keeps track of

我们已经完成的悬空或循环智能指针引用的一种解决方案是自定义智能指针类以添加仅调试的簿记功能。每当一个智能指针添加一个对象的引用时,它会采用堆栈跟踪并将其放入一个地图中,每个条目都跟踪一个

  1. The address of the object being allocated (what the pointer points to)
  2. 被分配对象的地址(指针指向的对象)

  3. The addresses of each smartpointer object holding a reference to the object
  4. 每个智能指针对象的地址,包含对象的引用

  5. The corresponding stacktraces of when each smartpointer was constructed
  6. 构建每个智能指针时的相应堆栈跟踪

When a smartpointer goes out of scope, its entry in the map gets deleted. When the last smartpointer to an object gets destroyed, the pointee object gets its entry in the map removed.

当smartpointer超出范围时,它在地图中的条目将被删除。当对象的最后一个smartpointer被破坏时,指针对象将其地图中的条目删除。

Then we have a "track leaks" command with two functions: '[re]start leak tracking' (which clears the whole map and enabled tracking if its not already), and 'print open references', which shows all outstanding smartpointer references created since the 'start leak tracking' command was issued. Since you can see the stack traces of where those smart pointers came into being, you can easily know exactly who's keeping from your object being freed. It slows things down when its on, so we don't leave it on all the time.

然后我们有一个带有两个函数的“track leaks”命令:'[re]启动泄漏跟踪'(清除整个地图并启用跟踪,如果还没有),'print open references',显示所有未完成的智能指针引用自从'start leak tracking'命令发布以来。由于您可以看到这些智能指针所在的堆栈跟踪,因此您可以轻松地确切知道谁将保留您的对象。当它打开时它会减慢速度,所以我们不会一直保持这种状态。

It's a fair amount of work to implement, but definitely worth it if you've got a codebase where this happens a lot.

这是一项相当多的工作要实现,但如果你有一个代码库,这种情况发生了很多,那绝对是值得的。

#4


You may be experiencing a shared pointer memory leak via cycles. What happens is your shared objects may hold references to other shared objects which eventually lead back to the original. When this happens the cycle keeps all reference counts at 1 even though no one else can access the objects. The solution is weak pointers.

您可能正在通过循环遇到共享指针内存泄漏。发生的事情是您的共享对象可能包含对其他共享对象的引用,这些对象最终会返回原始对象。发生这种情况时,即使没有其他人可以访问对象,循环也会将所有引用计数保持为1。解决方案是弱指针。

#5


Try refactoring some of your code so that ownership is more explicitly expressed by the use of weak pointers instead of shared pointers in some places.

尝试重构一些代码,以便通过在某些地方使用弱指针而不是共享指针来更明确地表达所有权。

When looking at your class hierarchy it's possible to determine which class really should hold a shared pointer and which merely needs only the weak one, so you can avoid cycles if there are any and if the "real" owner object is destructed, "non-owner" objects should have already been gone. If it turns out that some objects lose pointers too early, you have to look into object destruction sequence in your app and fix it.

在查看类层次结构时,可以确定哪个类确实应该保存共享指针,哪些只需要弱指针,因此如果存在任何类,并且“真正的”所有者对象被破坏,则可以避免循环,“非所有者“对象应该已经消失了。如果事实证明某些对象过早丢失指针,则必须在应用程序中查看对象销毁序列并进行修复。

#6


You're obviously holding onto references to your objects within your application. This means that you are, on purpose, keeping things in memory. That means, you don't have a memory leak. A memory leak is when memory is allocated, and then you do not keep a reference to its address.

您显然在应用程序中持有对对象的引用。这意味着您有意将事物记忆在内。这意味着,您没有内存泄漏。内存泄漏是在分配内存时,然后您不保留对其地址的引用。

Basically, you need to look at your design and figure out why you are keeping so many objects and data in memory, and how can you minimize it.

基本上,您需要查看您的设计并找出为什么要在内存中保留如此多的对象和数据,以及如何将其最小化。

The one possibility that you have a pseudo-memory leak is that you are creating more objects than you think you are. Try putting breakpoints on all statements containing a 'new'. See if your application is constructing more objects than you thought it should, and then read through that code.

您有伪内存泄漏的一种可能性是您创建的对象比您想象的要多。尝试在包含'new'的所有语句上添加断点。查看您的应用程序是否构建了比您预期的更多的对象,然后阅读该代码。

The problem is really not so much a memory-leak as it is an issue of your application's design.

问题实际上不是内存泄漏,而是因为它是应用程序设计的问题。

#7


I was going to suggest using UMDH if you are on windows. It is a very powerful tool. Use it find allocations per transaction/time-period that you expect to be freed then find who is holding them.

如果你在Windows上,我打算建议使用UMDH。这是一个非常强大的工具。使用它查找您希望被释放的每个事务/时间段的分配,然后查找持有它们的人。

There is more information on this SO answer Find memory leaks caused by smart pointers

有关此SO答案的更多信息查找由智能指针引起的内存泄漏

#8


It is not possible to tell what objects own shared_ptr from within the program. If you are on Linux, one sure way to debug the memory leaks is the Valgrind tool -- while it won't directly answer your question, it will tell where the memory was allocated, which is usually sufficient for fixing the problem. I imagine Windows has comparable tools, but I am do not know which one is best.

无法从程序中分辨出哪些对象拥有shared_ptr。如果你在Linux上,调试内存泄漏的一种可靠方法是Valgrind工具 - 虽然它不会直接回答你的问题,但它会告诉你内存的分配位置,这通常足以解决问题。我想Windows有类似的工具,但我不知道哪一个是最好的。