Memory problem using shared_ptr w/ STL-containers, gcc
Hi,
I have a somewhat peculiar problem concerning the shared_ptr template.
I use an STL container to hold several shared_ptr values. When the
container is destroyed, all the destructors are called correctly, but
the memory is not freed. Furthermore, shared_ptr usage introduces a
100x memory overhead (or more) in my case. Compiler system is GCC.
Consider the following short example:
#include <iostream>
#include <string>
#include <deque>
#include
Hey Robert, If you change your A class to look like this: class A { public: A(int iID) : a(iID) {} ~A() { std::cout << "Destroying " << a << std::endl; } int a; int b; }; You'll see that the objects are or are not getting destroyed (they are on my comp). I played around with this in VC 8 and the memory usage didn't go up like yours. Here's how it looks on my system: With n = 10 ----------------------- In release mode Pre: 1,336K After new's: 1,336K After deletes: 1,336K In debug mode Pre: 1,640K After new's: 1,652K After deletes: 1,652K With n = 100,000 ----------------------- In release mode Pre: 1,336K After new's: 10,568K After deletes: 1,432K In debug mode: Pre: 1,640K After new's: 20,668K After deletes: 1,776K So, at least on my computer there isn't a memory leak, but it's hard to tell that when using such a small n. While mine did go up with n = 10 in release mode, it didn't go up 150k, that seems like a lot to me! Maybe someone with a better understanding of memory usage could give you a better explanation as to what's really going on, but I don't think you have a real memory leak. Maybe try it without the shared_ptr, just a list of A objects and see how your memory does then, but increase the size of your A class to compensate for the shared_prt not being stored (which is an unsigned int and a pointer, so 8 bytes on a 32bit machine). Regards, Daniel
-----Original Message----- From: boost-users-bounces@lists.boost.org [mailto:boost-users- bounces@lists.boost.org] On Behalf Of Robert Fendt Sent: Thursday, October 19, 2006 10:25 AM To: boost-users@lists.boost.org Subject: [Boost-users] Memory problem using shared_ptr w/ STL- containers,gcc
Hi,
I have a somewhat peculiar problem concerning the shared_ptr template. I use an STL container to hold several shared_ptr values. When the container is destroyed, all the destructors are called correctly, but the memory is not freed. Furthermore, shared_ptr usage introduces a 100x memory overhead (or more) in my case. Compiler system is GCC.
.. snip ..
Between the first and the second stop, the program size in memory
grows
by about 150k... and that's for 10 objects which are <20 bytes large, individually. And to top it off, it leaks memory. Between stops two and three the memory *should* be freed since the scope is left. I can include a destructor doing debug output in the class which shows that the objects are indeed destroyed. But the memory stays allocated.
I suspect this is a GCC problem, but I have actually no clue... I tested it on a recent Debian "Unstable" and an Ubuntu "Breezy". GCC versions varying from 3.2 to 4.1. Or do I use the template in a wrong way? Suggestions would be very welcome... and if this is a known bug in GCC, a feasible work-around would be great.
Thanks in advance, Robert
Disclaimer - This email and any files transmitted with it are proprietary and may contain privileged or copyright information. You must not present this message to another party without gaining permission from the sender. If you are not the intended recipient you must not copy, distribute or use this email or the information contained in it for any purpose other than to notify us. If you have received this message in error, please notify the sender immediately, and delete this email from your system. We do not guarantee that this material is free from viruses or any other defects although due care has been taken to minimize the risk. eSafe scanned this email for viruses, vandals and malicious contentAny views expressed in this message are those of the individual sender, except where the sender specifically states them to be the views of LSI. **********************************************************************************************
And thus spake "Baranowski, Daniel"
You'll see that the objects are or are not getting destroyed (they are on my comp). I played around with this in VC 8 and the memory usage didn't go up like yours. Here's how it looks on my system:
Well, I have to apologise in one respect, the memory definitely gets re-used, which is a relief. What remains is the impossibly-large memory footprint of >10kb per object, which I have to investigate further. At the moment it is such that a list of a little over 5000 (small) POD objects eats well over 100MB of memory, and that just can't be right... however I will check if this is really caused by the shared_ptr... Anyway, thank you all for your suggestions and your time. You have been a great help. Regards, Robert
And thus spake Robert Fendt
Well, I have to apologise in one respect, the memory definitely gets re-used, which is a relief. What remains is the impossibly-large memory footprint of >10kb per object, which I have to investigate further. At the moment it is such that a list of a little over 5000 (small) POD objects eats well over 100MB of memory, and that just can't be right... however I will check if this is really caused by the shared_ptr...
Okay, and now the second part of the mystery was revealed. I am almost too embarrassed to tell... let's just say implementing classes at 3:00 in the morning is almost never a good idea... there is a time_date member in the class, and since I have to be able to set the time via an input string (and because time_date can use streams quite beautifully) there is of course need for a stringstream... To make a long story short: PEBKAC. Or "it appeared like a good idea at the time (i.e., 3:00) to make the conversion stream non-static". IOW: every object got its own stream, which of course blew the size in memory totally out of proportion. Add to that the behaviour of the GCC runtime that even large chunks of memory are usually *not* released to the system but rather held in a memory pool for re-allocation, the confusion was perfect. At first glance the effect was seemingly replicated even in my small test case, but this was not the case. So this is neither a bug in Boost nor in GCC. Thank you all, Robert
Robert Fendt wrote:
Hi,
I have a somewhat peculiar problem concerning the shared_ptr template. I use an STL container to hold several shared_ptr values. When the container is destroyed, all the destructors are called correctly, but the memory is not freed. Furthermore, shared_ptr usage introduces a 100x memory overhead (or more) in my case. Compiler system is GCC.
Does it also happen with libstdc++'s own std::tr1::shared_ptr in
Robert Fendt wrote:
Hi,
I have a somewhat peculiar problem concerning the shared_ptr template. I use an STL container to hold several shared_ptr values. When the container is destroyed, all the destructors are called correctly, but the memory is not freed. Furthermore, shared_ptr usage introduces a 100x memory overhead (or more) in my case. Compiler system is GCC.
I am not sure this is entirely unexpected. A shared pointer contains 2
pointers. One points to the object stored, while the other points to a
structure containing a variety of information regarding the object
(called shared_count). The fields I can think of in this structure
follow:
- The number of shared pointers referencing this object
- The number of weak pointers referencing this object
- A pointer to the object, expressed as the original type used to create
the shared pointer (To prevent deleting using a pointer to a base class
which may not have a virtual destructor).
- A pointer to a deleter routine, used if you shouldn't use the delete
operator when you're done with the pointer.
In addition, I remember reading that on several platforms, the
shared_count structures are actually allocated using a pool allocator,
as malloc and/or new aren't well suited to allocating numerous small
structures. This would cause an even larger allocation, as the pool
would allocate enough memory for several dozen structures.
As for the fact that you didn't see the memory getting released, that
could also be explained by the pool. Then the objects are destroyed,
the shared_count structures are returned to the pool to be used later,
but, as far as the operating system is concerned, they were not freed.
I am also curious what you mean by "program size in memory." Was this
the amount of memory allocated to the program by the operating system?
It has often been my experience that allocation of memory doesn't
exactly mirror the individual allocations of objects; the operating
system generally allocates a few (relatively large) pages, which the C
runtime library then splits into individual objects. It has also been
my experience that these pages are rarely reclaimed from a running
program.
You might consider testing this by inserting a loop round the code that
fills the deque, like so:
#include <iostream>
#include <string>
#include <deque>
#include
Between the first and the second stop, the program size in memory grows by about 150k... and that's for 10 objects which are <20 bytes large, individually. And to top it off, it leaks memory. Between stops two and three the memory *should* be freed since the scope is left. I can include a destructor doing debug output in the class which shows that the objects are indeed destroyed. But the memory stays allocated.
Thanks in advance, Robert
participants (4)
-
Andrew Holden
-
Baranowski, Daniel
-
Peter Dimov
-
Robert Fendt