Solved

Why are my static variables reported as leaking memory?

Posted on 1998-04-27
18
516 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
 
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
What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

 
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 90 total points
ID: 1164675
Thanks; your kindness is uncommon for Experts Exchange.

.B ekiM

0

Featured Post

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

Here is a helpful source code for C++ Builder programmers that allows you to manage and manipulate HTML content from C++ code, while also handling HTML events like onclick, onmouseover, ... Some objects defined and used in this source include: …
This article shows you how to optimize memory allocations in C++ using placement new. Applicable especially to usecases dealing with creation of large number of objects. A brief on problem: Lets take example problem for simplicity: - I have a G…
The viewer will learn how to use and create keystrokes in Netbeans IDE 8.0 for Windows.
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…

757 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

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now