[Last Call] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

Why are my static variables reported as leaking memory?

Posted on 1998-04-27
18
Medium Priority
?
566 Views
Last Modified: 2013-12-14
I am using VC++5 with SP3.  I am not using MFC.

I have a non MFC dll that uses the multi threaded runtime DLL, written in C++.  In some of my functions I have static data.  When my DLL exits, the memory allocated by these statics (and deallocated in their desturctors) are being reported as being leaked.  Why is this?  I can trace and see that the destructors are being called.  I even put a breakpoint on the operator delete and witnessed (in the debugger) that this was being deleted.
0
Comment
Question by:danny_pav
  • 7
  • 6
  • 4
  • +1
18 Comments
 
LVL 22

Expert Comment

by:nietod
ID: 1164658
who is reporting that the memory is leaking?

Note that at the time that the Dll's entry pointer function is called to indicate that the Dll is detaching from the process, the memory will still be in use.  The statics are not destroyed until after the DllMain()/DllEntryPoint() function returns.
0
 

Expert Comment

by:bleibold
ID: 1164659
Make sure that your application using the DLL and the DLL itself are both using the same UNICODE or ANSI compile options.  If one and not the other happens to be using the UNICODE option, then both runtime libraries (non-UNICODE and UNICODE) will get called and upon destruction resource leaks will inadvertently be reported from one of the runtime libraries.  If this is the case, then the resource leaks being reported are false.
0
 
LVL 11

Expert Comment

by:mikeblas
ID: 1164660
The memory is reported as leaked because it is freed after MFc terminates. MFC causes the C Runtime to report all things allocated and not freed at the time MFC terminates as being leaked. The report is generated before your destructors run and your objects have a chance to free their memory.

(You can show yourself that this is the case by putting some breakpoints on your destructors. You'll see that the leak trace is made before your breakpoints are hit.)

You can allocate the memory with calls that aren't tracked by the runtimes (by calling non-debug versions of the allocator, for example, or by calling the Windows API directly) in order to avoid the problem. Check out MFC's own CNoTrackObject for an example of this technique.

Or, you can read up on the C Runtime debug reporing APIs and use them to reset the checkpoint used by MFC's leak reporting.

.B ekiM

0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
LVL 11

Expert Comment

by:mikeblas
ID: 1164661
Sorry, I thought I read that you _were_ using MFC.

It turns out the diagnosis is the same: the C Runtime is deciding to report leaks before your static destructors have actually run.

The workaround is the same, too: you can either move the checkpoint the runtimes are placing, or you can use allocation mechanisms that don't engage the runtime's tracking support.

Additionally, you can use #pragma init_seg() to have your static objects initialize later (and therefore destruct earlier). That may or may not be appropriate for your application--it really depends on what your application is doing with those static objects and what exact lifetime expectations you have.

.B ekiM

0
 
LVL 22

Expert Comment

by:nietod
ID: 1164662
That doesn't make sense to me Mike.  I have a Dll that has static objects that use dynamic memory and I have never seen this problem.  I do see reports of memory leaks, when they are really there, but not related to my statics.

How do you move the check the run-time is doing?  I thought it was done automatically when the program terminates.
0
 
LVL 3

Author Comment

by:danny_pav
ID: 1164663
Here is the simplified example:

#include <string>
typedef std::basic_string<TCHAR> c_tstring;

void save_first(LPCTSTR lpsz) {
  static c_tstring s;
  if (s.length() == 0)
  {
    s.assign(lpsz);
  }
...
}

when the dll terminates, there are memory leaks reported.  I put breakpoints on the operator new and found that the memory being reported as leaked (which was at the same address each run) was being allocated by basic_string's ctor.  I then put a breakpoint on operator delete and did see the memory at that address being deallocated by basic_string's dtor.

Dan

0
 
LVL 22

Expert Comment

by:nietod
ID: 1164664
According to mike that is because the memory leak report is being made before the static destcrutors are being called.  Can you verify that?  Do you see the report being made before your breakpoint on the destructor or delete is called?  I've never seen that happen.  I get the memory leak reports after the statics are destroyed.  That's why I'm skeptical about Mike's answer.
0
 
LVL 11

Expert Comment

by:mikeblas
ID: 1164665
You don't move the runtime check, you move the checkpoint the runtime library is referencing as the baseline for allocated memory. That you've not seen the problem before doesn't mean it doesn't exist.

Since the problem is with a static that isn't in a user-defined class, you're really out-of-luck for the suggestions I've offered.

Let me see if I can repro the problem and come up with any snappy ideas. (Do you want to post a reference to a complete, minimal project to save me that time?)

.B ekiM

0
 
LVL 11

Expert Comment

by:mikeblas
ID: 1164666
Oh, and when you call your save_first() entry point, who owns the memory you're passing the function?  How was it allocated?  You're calling this function from the program that loads the DLL, is that right?

.B ekiM

0
 
LVL 22

Expert Comment

by:nietod
ID: 1164667
How do you move this checkpoint?  I would assume it is the state of the heap before anything is added to it.  i.e. empty.
0
 
LVL 3

Author Comment

by:danny_pav
ID: 1164668
What makes this easier is that the same memory leak report is generated each time.  So, I set 3 breakpoints
1 dbgheap.c, line 249 when pvBlk == <offending leaking address>,
2 dbgheap.c, line 1934
3 delop.cpp  line 7 when p == <offending leaking address>,

Breakpoint 1 is hit when the static object's constructor allocates the object's memory.
breakpoint 2 is hit during the memory dump.
breakpoint 3 is hit during the destructor of the static object
0
 
LVL 3

Author Comment

by:danny_pav
ID: 1164669
I got the answer from MS Web response support:
Hello Daniel,
I created a sample application to match the way you have built your application; i.e I called the C++ dll from an MFC application. I was able to reproduce to the behaviour that you reported and I was also able to figure out the reason for this
behaviour.
It turns out that when the mfc dll gets unlaoded from memory, it checks for memory leaks using the crt memory check facilities. If the mfc dll is unloaded before your  dll that contains the static data, it will incorrectly  report the static data in your dll as a memory leak (because the static data in your dll hasn't been
destroyed yet).
The dlls get loaded in the order in which their import libraries are specified on the link line for the build and the dll that is loaded first gets  unloaded last.
When you build an mfc application from within the IDE, you don't have to explictly specify the import libraries needed but you specify the additional import library for your dll. In order
to control the order in which the import libraries are linked with the app (and hence the order in which the dlls are loaded), you need to follow these steps:

1. If the dll project and the calling mfc app are in the same workspace, choose the dll project's settings and check "Ignore export library" from the Project Settings Link tab.

2. You need to explicitly specify the import libraries needed for the client mfc application. In order to do determine what libraries are needed for your mfc application:
a. Choose Project->Settings->Link for the mfc project. In the "Project Options" edit box add the /verbose switch to the linker options.
b. Now build the mfc app. In the build output window, the linker will list out the default libs used e.g  Processed /DEFAULTLIB:mfc42d.lib
c. Make a note of all the default libs listed.

3. Now go back to Project->Settings->Link for the mfc project and:
a. Remove the /verbose switch from the "Project Options" edit box
b. Check the "ignore all default libraries" on the Link tab
c. In the Object/Library modules, specify the default libs seperated by space (e.g mfc42d.lib mfcs42d.lib msvcrtd.lib kernel32.lib user32.lib gdi32.lib
comdlg32.lib winspool.lib advapi32.lib shell32.lib comctl32.lib uuid.lib ........)
d. At the end of the default list add the import library for your dll that conatins the static objects. Make sure that your the import lib for your dll is the last one specified.

This will make sure that your dll is the last to be loaded in memory and the first to be unloaded. Now when the mfc dll gets unloaded, your dll would have already been unloaded and therefore
no memory leaks will be reported.

MORE INFO AVAILABLE AT: http://www.webresponse.microsoft.com/wr_bin/wr.asp?SR=SRZ980427000535
0
 
LVL 11

Expert Comment

by:mikeblas
ID: 1164670
Uh, but you said you weren't using MFC.

And the engineer thought you were--it's all over his answer.  (And, furthermore, the engineer opened a bug against MFC for the behaviour, which is completely by-design! Now, I've got to talk sense into the engineer, as well!)

.B ekiM


0
 
LVL 3

Author Comment

by:danny_pav
ID: 1164671
Mike:
Sorry for the confusion.  The DLL was non MFC. The testing client app was using MFC.
Dan
0
 
LVL 11

Expert Comment

by:mikeblas
ID: 1164672
Oh, I see.  So, why did you say you weren't using MFC?

.B ekiM
0
 
LVL 3

Author Comment

by:danny_pav
ID: 1164673
I meant that the dll was not using MFC.  The client app was only meant to test the DLL.  I needed a window handle for the functions I was testing, so I created the quickest app I could: a dialog based AppWizard MFC app.  I assumed that this would create an app free of bugs.  (It did, but in conjunction with my DLL, these problems occurred. ) Since I felt that the tesing app was of no consequence (I could have created an SDK app instead to test it) I assumed that there could be no problem with it.
Danny Pav
0
 
LVL 3

Author Comment

by:danny_pav
ID: 1164674
Mike B.  
After re-reading this thread, your answer matched with the answer I got from MS.  Having already rejected the original answer, how do I go back and accept that?
Danny

0
 
LVL 11

Accepted Solution

by:
mikeblas earned 270 total points
ID: 1164675
Thanks; your kindness is uncommon for Experts Exchange.

.B ekiM

0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction This article is a continuation of the C/C++ Visual Studio Express debugger series. Part 1 provided a quick start guide in using the debugger. Part 2 focused on additional topics in breakpoints. As your assignments become a little more …
How to install Selenium IDE and loops for quick automated testing. Get Selenium IDE from http://seleniumhq.org Go to that link and select download selenium in the right hand column That will then direct you to their download page. From that p…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.
Suggested Courses

830 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question