I have done the usual DEBUG_NEW stuff in all the files of the MFC exe and
DLLs. that usually does the trick but this time it isn't telling me about
it.
The problem may be in a non-MFC DLL. Any suggestions for how to find it?
[Years ago I had Bounds Checker but it got to be too expensive upgrading it
every time a new version of Windows became current, but DEBUG_NEW has been
ok for me ever since.]
Dave
--
David Webber
Author of 'Mozart the Music Processor'
http://www.mozart.co.uk
For discussion/support see
http://www.mozart.co.uk/mzusers/mailinglist.htm
> I have a small memory leak which is driving me mad!
>
> I have done the usual DEBUG_NEW stuff in all the files of the MFC exe
> and DLLs. that usually does the trick but this time it isn't telling me
> about it.
>
> The problem may be in a non-MFC DLL. Any suggestions for how to find it?
How do you know about the leak? Do you see the memory leak dump in the IDE's
output window when your application exits?
If yes then you have a good chance. You can set a memory breakpoint on the
allocation ID that is listed in the memory leaks dump. Add a call to
_CrtSetBreakAlloc(<put the ID here>); at the beginning of main()
Norbert
> How do you know about the leak? Do you see the memory leak dump in the
> IDE's
> output window when your application exits?
Yes.
> If yes then you have a good chance. You can set a memory breakpoint on the
> allocation ID that is listed in the memory leaks dump. Add a call to
> _CrtSetBreakAlloc(<put the ID here>); at the beginning of main()
Thank you! I have never needed that before. I now know where the leak
is, but not why.
But the plot thickens:
In my non-MFC DLL I have a global instance of an object of the form
CMyCollection : public std::vector<CMyThing>;
Its normal constructor is called on startup, which just creates and empty
collection.
It is only called once.
It is filled in (also once) with a method of CMyColllection schematically of
the form
CMyCollection::FillIn()
{
CMyThing thing;
for( allthings )
{
thing = .... // fill in the thing
push_back( thing ); //*********
}
}
It is usually not changed, and lasts until the program shuts down.
It is never copied. (It has a copy constructor, because I feel nervous
without them, but it is never called.)
The destructor is called once, and just calls clear() (because I feel it
is neat to do so).
I am being told that the memory leak is associated with the CMyThing's copy
constructor invoked by push_back() above.
How can that be?
Even stranger, I have had all of this present in the code for years and a
memory leak has only been reported recently.
Any ideas gratefully received.
"David Webber" <da...@musical-dot-demon-dot-co.uk> ha scritto nel messaggio
news:untsc43C...@TK2MSFTNGP02.phx.gbl...
> CMyCollection : public std::vector<CMyThing>;
[...]
Could you please try to use a Has-A "embedding" relationship (not Is-A via
inheritance), i.e. : putting a private/protected instance of
std::vector<CMyThing> into CMyCollection.
> CMyCollection::FillIn()
> {
>
> CMyThing thing;
>
> for( allthings )
> {
> thing = .... // fill in the thing
> push_back( thing ); //*********
> }
> }
>
[...]
> I am being told that the memory leak is associated with the CMyThing's
> copy constructor invoked by push_back() above.
>
> How can that be?
It would be interesting to see some code for CMyThing... (maybe it has got
some non-smart pointers that are not correctly copied, or it hasn't got a
virtual destructor that would be required...).
Also, you should pay attention about the C/C++ run-time used by each module
(DLLs and EXE).
I think it should be the same (e.g. debug multithreaded DLL, or
multithreaded DLL for release builds).
> Even stranger, I have had all of this present in the code for years and a
> memory leak has only been reported recently.
Maybe you are now using VS2005 which implements better checking for memory
leaks than VC6 or 2003...
Ciao
Giovanni
> In my non-MFC DLL I have a global instance of an object of the form
>
> CMyCollection : public std::vector<CMyThing>;
>
> Its normal constructor is called on startup, which just creates and
> empty collection.
> It is only called once.
> It is filled in (also once) with a method of CMyColllection
> schematically of the form
>
> CMyCollection::FillIn()
> {
>
> CMyThing thing;
>
> for( allthings )
> {
> thing = .... // fill in the thing
> push_back( thing ); //*********
> }
> }
>
> It is usually not changed, and lasts until the program shuts down.
> It is never copied. (It has a copy constructor, because I feel nervous
> without them, but it is never called.)
> The destructor is called once, and just calls clear() (because I feel
> it is neat to do so).
>
> I am being told that the memory leak is associated with the CMyThing's
> copy constructor invoked by push_back() above.
>
> How can that be?
If the memory leak is associated with CMyThing's copy constructor then I guess
it contains some deep copy opearions? If you overrode the CMyThing's copy
constructor, did you also override it's assignment operator and destructor? See
the "Law of the Big Three".
http://www.artima.com/cppsource/bigtwo.html
Norbert
> "David Webber" <da...@musical-dot-demon-dot-co.uk> ha scritto nel messaggio
> news:untsc43C...@TK2MSFTNGP02.phx.gbl...
[...]
>> CMyCollection::FillIn()
>> {
>>
>> CMyThing thing;
>>
>> for( allthings )
>> {
>> thing = .... // fill in the thing
>> push_back( thing ); //*********
>> }
>> }
>>
> [...]
>> I am being told that the memory leak is associated with the CMyThing's
>> copy constructor invoked by push_back() above.
One more thing: reading the above code, it seems that this is not the case,
but maybe you posted a simplification of real code. So: I think that you
should also pay attention about *where* (i.e. which module) you
allocate/free data.
i.e. I think that if you allocate something in the heap from module X (e.g.
a given DLL), you should also free that in the *same* module X.
I'm not sure, but I think it is not safe to allocate something in the heap
from module X, and free in module Y.
Giovanni
> One more thing: reading the above code, it seems that this is not the
> case, but maybe you posted a simplification of real code. So: I think that
> you should also pay attention about *where* (i.e. which module) you
> allocate/free data....
Thanks! This is the way I am starting to think too - see other post. With
the class being global in the DLL I am not in control of where it is
constructed and destroyed. I propose to do something about that tomorrow -
it's late now.
Dave
--
David Webber
Author of 'Mozart the Music Processor'
http://www.mozart.co.uk
For discussion/support see
http://www.mozart.co.uk/mzusers/mailinglist.htm
.
> If the memory leak is associated with CMyThing's copy constructor then I
> guess it contains some deep copy opearions?
Not particularly deep...
> If you overrode the CMyThing's copy constructor, did you also override
> it's assignment operator and destructor? See the "Law of the Big Three".
> http://www.artima.com/cppsource/bigtwo.html
... and yes - I am particular to the point of pedantry about that sort of
thing.
But explaining the problem has given me an idea.
Here's some real code:
=========================
#ifdef MZW32N_EXPORTS
#define MZWN_API __declspec(dllexport)
#define EXTERN_MZWN_API
#else
#define MZWN_API __declspec(dllimport)
#define EXTERN_MZWN_API extern
#endif
#include "percussion.h"
#include <vector>
#pragma warning( disable: 4251 ) // These are annoying.
#pragma warning( disable: 4231 ) // MSDN article Q168958 tells me to ignore
this warning.
// Instantiate a vector:
// This seems to be necessary if the class derived from vector is to be
exported.
EXTERN_MZWN_API template class MZWN_API
std::allocator<CPercussionInstrument>;
EXTERN_MZWN_API template class MZWN_API std::vector<CPercussionInstrument>;
// class CPercussionSet
class MZWN_API CPercussionSet : public std::vector<CPercussionInstrument>
{
public:
CPercussionSet();
CPercussionSet( const CPercussionSet &ps );
virtual ~CPercussionSet();
CPercussionSet & operator = ( const CPercussionSet &ps );
//....
};
=============
I am pretty sure the copy constructor, destructor, and assignment of
CPercussionInstrument are ok (I am checking). I *am* a little concerned
about exporting this class from the DLL, (in which the only instance is
global) and wondering if that is at the root of things. It may not be
being correctly destroyed when the DLL is unloaded - though the destructor
*is* getting called.
Perhaps I should store a global; pointer to a CPercussionSet and explicitly
create and destroy it with new and delete. That way I'd have more control
over when it happens! I'll experiment.
Dace:
What happens if you call clear() on your vector from somewhere else
(like ExitInstance()) rather than waiting for your derived destructor to
do it.
Actually, I don't think calling clear() from the destructor is
necessary, because the destructors of the contained objects are
automatically called by the std::vector destructor. I think the problem
is that your derived constructor is getting called too late relative to
the leak reporting mechanism.
--
David Wilkinson
Visual C++ MVP
That's what I thought also, but then why would it only start happening
recently when nothing has changed?
-- David
>In my non-MFC DLL I have a global instance of an object of the form
That is the key sentence.
>CMyCollection : public std::vector<CMyThing>;
>
>Its normal constructor is called on startup, which just creates and empty
>collection.
>It is only called once.
>It is filled in (also once) with a method of CMyColllection schematically of
>the form
>
>CMyCollection::FillIn()
>{
>
> CMyThing thing;
>
> for( allthings )
> {
> thing = .... // fill in the thing
> push_back( thing ); //*********
> }
>}
>
>It is usually not changed, and lasts until the program shuts down.
>It is never copied. (It has a copy constructor, because I feel nervous
>without them, but it is never called.)
>The destructor is called once, and just calls clear() (because I feel it
>is neat to do so).
>
>I am being told that the memory leak is associated with the CMyThing's copy
>constructor invoked by push_back() above.
>
>How can that be?
>
>Even stranger, I have had all of this present in the code for years and a
>memory leak has only been reported recently.
For some reason, your non-MFC DLL is loading before the MFC DLL now, and
during program termination, MFC is calling its "dump_spurious_leaks()"
function before your DLL has gotten the chance to destroy its globals.
>Any ideas gratefully received.
See these messages for an explanation and workaround:
http://groups.google.com/group/microsoft.public.vc.mfc/msg/990674e598690af9
http://groups.google.com/group/microsoft.public.vc.language/msg/6b90e68f21529e56
--
Doug Harrison
Visual C++ MVP
> On Wed, 10 Oct 2007 21:37:33 +0100, "David Webber"
> <da...@musical-dot-demon-dot-co.uk> wrote:
>
>>In my non-MFC DLL I have a global instance of an object of the form
>
> That is the key sentence.
>...
> See these messages for an explanation and workaround:
>
> http://groups.google.com/group/microsoft.public.vc.mfc/msg/990674e598690af9
> http://groups.google.com/group/microsoft.public.vc.language/msg/6b90e68f21529e56
Thanks Doug,
That appears to explain just about everything. And it makes me very
happy, because it means I did not program a memory leak - and thus delays
the fall I expect following my pride in never doing so :-)
I try to avoid global objects like the plague and this was my only infection
in this DLL. Most of my stuff which really needs to be global is stored
as a static pointer in a class, and the object is created by my InitInstance
code and explicitly deleted on ExitInstance. Once Norbert had told me how
to find it, the coincidence of global object and (apparent) memory leak
started ringing alarm bells.
I am now restructuring to handle this object like the others - which should
cure it as the memory will be freed from a call made by the MFC module.
Onward and upward.
> "David Wilkinson" <no-r...@effisols.com> wrote in message
> news:uGN8JT5C...@TK2MSFTNGP03.phx.gbl...
>> What happens if you call clear() on your vector from somewhere else (like
>> ExitInstance()) rather than waiting for your derived destructor to do it.
I do that anyway - which is another puzzle.
>> Actually, I don't think calling clear() from the destructor is necessary,
>> because the destructors of the contained objects are automatically called
>> by the std::vector destructor. I think the problem is that your derived
>> constructor is getting called too late relative to the leak reporting
>> mechanism.
>>
>
> That's what I thought also, but then why would it only start happening
> recently when nothing has changed?
That is a puzzle too - unless I have accidentally changed a setting in the
project which causes it to be reported. I don't *think* I have.
It isn't very serious. It is a bit of memory which should be used unchanged
(mostly) for the duration of the program, so having the system free it on
exit, isn't a disaster. But it's sloppy and I just *hate* it!
[The only time the memory is changed is when someone changes language
options: the instruments are unloaded and reloaded with their names in the
new language.]
>>In my non-MFC DLL I have a global instance of an object of the form
>
> That is the key sentence.
> ...
All fixed now - thanks again to everyone.
Thanks to you because we (or at least, I) learnt important lessons from your
post, like how super-important is to avoid global variables.
Giovanni
In that case, it seems to me that the leak must be the memory allocated
for std::vector itself, rather than any memory internal to your CMyThing
objects.
What happens if you also shrink the vector to zero capacity (using the
swap trick)?
> Thanks to you because we (or at least, I) learnt important lessons from
> your post, like how super-important is to avoid global variables.
Yes I have told myself that many times. It is my punishment for not taking
enough notice :-)
> In that case, it seems to me that the leak must be the memory allocated
> for std::vector itself, rather than any memory internal to your CMyThing
> objects.
I am rather concerned that I might know why. Well -ish. As I have an MFC
program with no main(), I put the _CrtSetBreakAlloc in the CWinApp drived
class constructor.
If the global vector object in the DLL was being constructed before the
CWinApp was constructed, it couldn't have actually stopped the program on
the vector's constuctor. The fact that it stopped when something was added
to the vector may have been a complete coincidence - in which case I've had
a monumental bit of luck :-(
So where does one put _CrtSetBreakAlloc to guarantee it is invoked before
absolutely anything is constructed?
>>[...] how super-important is to avoid global variables.
>
> Yes I have told myself that many times. It is my punishment for not
> taking enough notice :-)
:)
Gio
Dave:
Constructing an empty vector does not assign any memory. When you add
things to it, the vector assigns memory and there may be additional
memory owned by the objects being placed in the vector.
I am not an expert on _CrtSetBreakAlloc(). I have always just used the
MFC DEBUG_NEW and have always been able to get rid of any leaks it
reported. But I don't use global objects.
There is another way.
http://msdn2.microsoft.com/en-us/library/w2fhc9a3(VS.80).aspx describes
setting the _crtBreakAlloc variable to the desired value instead of calling
_CrtSetBreakAlloc(). So just step into your code in the debugger so it
stops at the entrypoint, then set this variable in the watch window.
OTOH, I'm not sure if it's too late once you step into your code... global
vars might have already been init. But you can try it.
BTW, I'm not sure why it's any concern because this is not a true memory
leak in that the memory is freed when the app is exited anyway. I
understand you don't like to see the mem leak output though, since it makes
it easy to ignore true memory leak output.
-- David
Your CWinApp derived class is a global object! :-)
-- David
> Constructing an empty vector does not assign any memory.
I'm not sure in what sense you mean this. Obviously if I put
CMyVector v;
Then &v will tell me where it is and sizeof v will tell me how big it is.
Ok, it is not being assigned dynamically but as a Global variable it sits
there and does not go out of scope until the program ends. In fact I have
always been rather vague on at what point its memory will be freed up,
because I have never really needed to know - until now :-)
> When you add things to it, the vector assigns memory and there may be
> additional memory owned by the objects being placed in the vector.
But each will have its own block of assigned memory and I only got 1 leak
with 200 odd objects.
> I am not an expert on _CrtSetBreakAlloc(). I have always just used the MFC
> DEBUG_NEW and have always been able to get rid of any leaks it reported.
> But I don't use global objects.
I too am a believer in DEBUG_NEW but this was happening in a non-MFC DLL.
:)
Yes, I was thinking about app class, too.
Maybe, in an elegant object-oriented designed system, the app instance
should be the only global object, and every other object should be created
by the app.
Giovanni
>I'm not sure, but I think it is not safe to allocate something in the heap
>from module X, and free in module Y.
It's fine if both modules link to the same CRT DLL. Given that David is
sharing C++ classes between modules, it's pretty much required.
David:
Yes, but I don't think its constructor assigns any memory.
I hope there is a better reason than to avoid spurious leak reporting by
MFC. :) It's not just "globals"; this problem affects any object that is
destroyed after MFC calls its "cause_spurious_leak_report()" function. For
example, MFC would have caused the same problem if the OP's vector had been
a static data member of one of the classes in his DLL.
When I said "That is the key sentence," the implied second part was,
"...that helps me identify the problem." I did not mean that having a
global object was the problem, just that "non-MFC DLL", "global object",
and mysterious "memory leaks" remind me of this long-standing MFC bug.
Dave:
But only heap memory contributes to memory leaks, yes? If the objects
you put in your vector do not themselves assign heap memory (i.e. use
new internally) they will not contribute to memory leaks. The only
possible leak will come from the memory assigned by the vector itself.
And this should be released by the destructor, because std::vector is a
well-behaved RAII class.
I think the problem is just that the destructor of your global object is
getting called too late (and Doug thinks so also, so this must be right...).
> But only heap memory contributes to memory leaks, yes?...
I wasn't sure of that.
> I think the problem is just that the destructor of your global object is
> getting called too late (and Doug thinks so also, so this must be
> right...).
Yes, it makes sense.