A MFC method for processing memory leakage

zhaozj2021-02-08  235

Ministry of Information Industry Data Institute Liao

---- Windows uses complex memory manager to control and optimize memory usage (including disk buffer). Once the memory management occurs, it will cause memory leakage. The substance of memory leaks is generally because a block is allocated on a pile, but it will not be reassigned in the future, so that the part memory loses reuse. Most applications in this issue are often running normally, so it is more difficult to detect this class problem. However, you have to find it and get the right process. Most MFC applications allow Windows to securely manage memory allocated to the resource, and if the component allocated memory is greatly increased by the risk of memory leaks from the system. Here are some related issues to discuss them.

Example: Multiple redraw windows cause memory leakage

---- We simply create an STD MFC engineering MLLAK, the program first creates a logical font, then the TextOut () function writes text in the client area of ​​the window, if the program is similar to Figure 1 () left, last longer, you also I can't see any strange phenomenon. However, you can use the mouse to grasp the boundary of the window to change the window size multiple (more time to do tens of times) will see the window turned into Figure 1: The font has a problem. The TextOut () function can still write text on the window, but logical fonts have not been created correctly. It is generally considered that the problem is in the font creation process in the onDraw () function. Is this like this?

Find and analyze problems

---- Fortunately, some MFC classes and functions can be used to discover memory leaks. Adding a corresponding code helps to check the memory leak problems in the CmleakView class (the key code is identified in bold). First we use ClassWizard to join the oncreate () function as the view class, with the purpose of obtaining the statistics of the stack when the program is initialized. As long as the OldMemState.CheckPoint () function can do this. Then, the onDraw () function will perform the following additional debug code after completing all the work related to the font:

#ifdef _Debug

NEWMEMSTATE.CHECKPOINT ();

IF (DiffMemState.difference

(OldMemState, NewMemState))

{

Trace ("Difference Between First and Now! / N / N");

DiffMemState.dumpstatistics ();

}

#ENDIF

---- Call newMemState.checkpoint () will get the latest situation of the heap, and DiffMemState.Difference () returns information when the original value and the current value are different. The statistical results were thrown out by calling DiffMemState.dumpStatistics (). Because this information is included in the onDraw () function, while the onDraw () function is in response to the WM_PAINT message to redraw the screen window, the statistical results will be printed at each change window, we discovers the last line of the statistics released every time. no change:

Difference Between first and now!

(The beginning of the first statistics)

...

Total Allocations: 87 bytes.

(End of the first statistics)

......

Total Allocations: 132 bytes.

(End of the second statistics)

...

Total Allocations: 14352 bytes.

(The end of the last statistics)

---- It can be noted that each redraw screen causes the entire allocation area to increase, an increase of 45 bytes, and the memory allocation is reached 14,352 bytes after rendering a certain number of times. So will it be forgot to assign memory for logical font structures? Let's insert the following bold code to the onDraw () function:

Logfont LF;

...

MEMSET (& lf, 0, sizeof (logfont)); ...

---- Results, indicating that the logical font structure is not associated with this. Remove the font creation process from the onDraw () function and add to OnCreate () to create a logical font resource to create a window, but you can also find that the entire memory of allocation is still increased! Then modify the onDraw () as follows:

Void cmleakview :: OnDraw (CDC * PDC)

{

Cmleakdoc * pdoc = getDocument ();

Ask_VALID (PDOC);

PDC-> Textout (20, 200,

"This Program Has Memory Problems";

#ifdef _Debug

NEWMEMSTATE.CHECKPOINT ();

IF (DiffMemState.difference

(OldMemState, NewMemState)) {

Trace ("Difference Between First and Now! / N / N");

DiffMemState.dumpstatistics ();

}

#ENDIF

}

---- The problem is still appearing, and the following code is the unique code added in onDraw ():

PDC-> Textout

(20, 200, "This Program Has Memory Problems);

---- Comment this line code and recompile, run the diagnostics. It can be found that the entire memory allocation statist results are 0. It seems that it is redistributed when there is a screen that is allocated to the string.

Memory diagnostic parameters

---- Enable or disable memory diagnostics to call global functions AFXENABLEMORYTRACKING (). Debugger will automatically control it, so the function will significantly add a program execution speed and reduce diagnostic information. The MFC global variable AFXMEMDF makes specific memory diagnostic features available. This variable information can be found in the relevant information.

Find memory leaks

---- We first implement a CMEMORYSTATE object (CMemoryState can be found). Call the checkpoint () function before entering a problem code to get the original situation of memory usage. Then implement another CMEMORYSTATE object and call the checkpoint () function after writing a problem code to get the memory used. Of course, the third CMEMORYSTATE object can also be implemented and the Difference () member function can be called. The previous two CMEMORYSTATE objects are called as their parameters when calling this function. If there is no difference before and after memory, the function return value is not 0. This can at least explain whether some memory blocks have not been released. The following is some of these three subjects:

#ifdef _Debug

CMemoryState OldMemState,

Newmemstate, DiffMemState;

OldMemState.checkpoint ();

#ENDIF

...

(The code tested)

...

#ifdef _Debug

NEWMEMSTATE.CHECKPOINT ();

IF (DiffMemState.difference

(OldMemState, NewMemState))

{

"" Memory Leaked Here: / N / N ");

}

#ENDIF

Memory status

---- CMemoryState () member function can be used to get statistics for current memory or differences in two memory object status. Also available to find memory leaks on the heap. The following code uses raw information to detect the current memory status:

"Current Memory Picture: / N / N");

NewmemState.dumpstatistics ();

---- It is easy to get the difference in memory status:

IF (DiffMemState.diference (OldMemState, NewMemState))

{

"" Memory Leaked Here: / N / N ");

DiffMemState.dumpstatistics ();

}

The sample output of DIFFMEMSTATE.DUMPSTATISTISTISTISTISTISTISTISTISTISTISTISTISTISTISTISTISTISTISTICS ()

0 bytes in 0 free blocks

2 Bytes in 1 Object Blocks

50 BYtes in 5 Non-Object Blocks

Largest Number Used: 76 Bytes

Total Allocations: 304 Bytes

---- The first line of the code indicates the number of memory blocks that delay release. This will be like this when the AFXMEMDF variable is set to DelayFreememdf. The second line is used to indicate how many objects are also present on the heap. The third line indicates how many non-object blocks (newly allocated) are assigned and is not released. The fourth line indicates the maximum memory used in a given time. The last line indicates all the memory used by the project. There is a problem with any problems in any one of the above means that the memory is leaking.

Repair engineering

---- Although the string in the onDraw () in the CMLAKVIEW class may also successfully solve the previous problem, but AppWizard has created a special class CmleakDoc document class responsible for storage and assignment. We can declare the restriction of the string to be displayed as a member variable of cmleakdoc in a MLEAKDOC.H file:

CString mycstring;

Then assign it in the constructor of CmleakDoc:

Cmleakdoc :: cmleakdoc ()

{

Mycstring = "this Program Doesn't Have a Leak";

}

The final repaired engineering documents are roughly as follows:

// mleakview.cpp:

Implementation of the cmleakview class

//

...

CFONT NFONT;

...

Void cmleakview :: OnDraw (CDC * PDC)

{

...

CFont * Pofont;

POFONT = PDC-> SelectObject (& nfont);

PDC-> TextOut (20, 200, pdoc-> mycstring);

DeleteObject (Pofont);

}

...

INT cmleakview :: oncreate

(Lpcreatestruct lpcreatestruct)

{

IF (cview :: oncreate (lpcreatestructure) == -1)

Return -1;

Logfont LF;

MEMSET (& lf, 0, sizeof (logfont));

Lf.lfheight = 50;

Lf.lfweight = fw_normal;

Lf.LFEScapement = 0;

Lf.LForientation = 0;

Lf.lfitalic = false;

Lf.lfunderline = false;

Lf.lfstrikeout = false;

Lf.lfcharset = ansi_charset;

Lf.lfpitchandfamily = 34; // arial

NFont.createFontIndirect (& lf);

Return 0;

}

---- Some technical means to make programmers have some new awareness of some hidden memory traps, but found and solve the problem of memory leaks, which is always required to be patient and careful, and experience may be heavier. In the technical guide.

转载请注明原文地址:https://www.9cbs.com/read-1363.html

New Post(0)