MFC cstring (vc6) Memory Management Analysis

Source: Internet
Author: User
Tags cplex

Source: csdn Author: Brant

The cstring class is a frequently used class, so it is necessary to analyze its memory management mode. The evolution of memory management is as follows:
 
Vc5 simply uses the new Delete method.
Because the memory size needs to be adjusted frequently for string operations, the C ++ operator new and delete have no function corresponding to realloc. The result is that an additional copy operation is required for every memory change. New and delete are allocated in the process heap in implementation. Frequent allocation and release of small memory on the stack will inevitably generate a large number of fragments on the stack. Too many heap fragments directly affectProgramEfficiency. So the MFC version was modified in vc6.
 
Vc6 uses new and delete to operate cstring in memory greater than 512 bytes and debug mode. In release mode, memory pool management is used for Memory Allocation Operations of no more than 512 bytes. And subdivided into four memory pools for management: <= 64, <= 128, <= 256, <= 512 bytes. In this way, cstring has a good efficiency when it is no more than 512 bytes. However, it is said that resolving a bug will produce the law of another bug.
Cstring cannot be avoided either. So it was changed again in vc7.

Vc7 resumes using C's memory management call method. That is, alloc, free, and realloc. cstring are used because new and delete do not have the realloc function to re-adjust the memory size. As a result, the C management method was adopted. In vc6, to solve the performance problem of cstring small memory manipulation, MFC optimized the memory pool management for memory allocation of no more than 512 bytes in the release version. In other cases, cstring in new and delete. Release versions is used to call the following when processing memory of strings not greater than Bytes:
In vc6, the calling sequence of cstring memory allocation and memory release is as follows: cstring: allocbuffer
Cfixedalloc: alloc
Cplex: createcstring: freedata
Cfixedalloc: free
Related Code Reference:
File: MFC \ SRC \ strcore. cpp
Void cstring: allocbuffer (INT nlen) // used to allocate memory
{
...
# Ifndef _ debug // In the release version and the value is no greater than 512 bytes
If (nlen <= 64)
{
Pdata = (cstringdata *) _ afxalloc64.alloc ();
Pdata-> nalloclength = 64;
}
Else is <= 1128, <= 256, <= 512
{
...
}
Else
# Endif // debug and release values greater than 512
{
Pdata = (cstringdata *)
New byte [sizeof (cstringdata) + (nlen + 1) * sizeof (tchar)];
Pdata-> nalloclength = nlen;
}
...
}
Void fastcall cstring: freedata (cstringdata * pdata) // release the memory.
{
# Ifndef _ debug is in the release version and cannot exceed 512 bytes
Int nlen = pdata-> nalloclength;
If (nlen = 64) // call the manager separately based on the memory size
_ Afxalloc64.free (pdata );
Else if (nlen = 128)
_ Afxalloc128.free (pdata );
Else if (nlen = 256)
_ Afxalloc256.free (pdata );
Else if (nlen = 512)
_ Afxalloc512.free (pdata );
Else
{
Assert (nlen> 512 );
Delete [] (byte *) pdata;
}
# Else // debug and release with a value greater than 512
Delete [] (byte *) pdata;
# Endif
}
_ Afxalloc [64,128,256,512] is a global object of the cfixedalloc class. Let's analyze what problems occurs when cfixedalloc is used to manage the memory pool in an integral way?
Class cfixedalloc // is defined in the MFC \ SRC \ fixalloc. h file.
{
Public:
Cfixedalloc (uint nallocsize, uint nblocksize = 64 );
Uint getallocsize () {return m_nallocsize ;}
Public:
Void * alloc (); // allocation is called by cstring
Void free (void * P); // release is called by cstring
Void freeall (); // release all destructor calls
Public:
~ Cfixedalloc ();
Protected:
Struct cNode {// This is used to implement a one-way linked list
CNode * pnext;
};
Uint m_nallocsize; // the size of the object to be allocated is passed in only by the constructor.
Uint m_nblocksize; // The pre-allocated quantity, that is, the size of the pool, which is assigned by the constructor. The default value is 64.
Cplex * m_pblocks; // linked list pointer of the pool. The cplex object contains a cplex * pnext pointer object,
CNode * m_pnodefree; // the header pointer of the released block linked list, which should be regarded as a list of available memory blocks.
Critical_section m_protect; // critical area object
};
/*
In the implementation of alloc, we can see that when there is no available block in the pool
Call cplex: Create to create a memory pool m_nallocsize * m_nblocksize
If there is one, a piece is popped up from m_pnodefree.
*/
Void * cfixedalloc: alloc ()
{
If (m_pnodefree = NULL) {// allocate a pool if no memory block is available
Cplex * pnewblock = NULL;
Try
{// The allocated memory block is 64 m_nallocsize by default.
Pnewblock = cplex: Create (m_pblocks, m_nblocksize, m_nallocsize );
}
Catch_all (E)
{
... Exception
} End_catch_all
// The following code pushes the memory block to the m_pnodefree linked list for use.
CNode * pnode = (cNode *) pnewblock-> data ();
(Byte * &) pnode + = (m_nallocsize * m_nblocksize)-m_nallocsize;
For (INT I = m_nBlockSize-1; I> = 0; I --, (byte * &) pnode-= m_nallocsize)
{
Pnode-> pnext = m_pnodefree;
M_pnodefree = pnode;
}
}
// A piece of memory is displayed for the caller.
Void * pnode = m_pnodefree;
M_pnodefree = m_pnodefree-> pnext;
...
Return pnode;
}
/*
When the caller calls free, the memory is only re-pushed into the m_pnodefree linked list.
It is not released, but marked as a usable block for future use.
*/
Void cfixedalloc: Free (void * P)
{
If (P! = NULL)
{
Entercriticalsection (& m_protect );
CNode * pnode = (cNode *) P;
Pnode-> pnext = m_pnodefree;
M_pnodefree = pnode;
Leavecriticalsection (& m_protect );
}
}
Void cfixedalloc: freeall ()
{
Entercriticalsection (& m_protect );
M_pblocks-> freedatachain ();
M_pblocks = NULL;
M_pnodefree = NULL;
Leavecriticalsection (& m_protect );
}
/*
Call freeall In the destructor to release the memory.
*/
Cfixedalloc ::~ Cfixedalloc ()
{
Freeall ();
Deletecriticalsection (& m_protect );
}
/*
MFC \ include \ afxplex_.h
*/
Struct cplex // warning variable length structure
{
Cplex * pnext;
Void * Data () {return this + 1 ;}
Static cplex * Pascal create (cplex * & head, uint Nmax, uint cbelement );
Void freedatachain (); // free this one and links
};/*
MFC \ SRC \ Plex. cpp
*/
Cplex * Pascal cplex: Create (cplex * & phead, uint Nmax, uint cbelement)
{
Cplex * P = (cplex *) New byte [sizeof (cplex) + Nmax * cbelement];
P-> pnext = phead;
Phead = P; // Add to the linked list
Return P;
}
Void cplex: freedatachain () // free this one and links
{
Cplex * P = this;
While (P! = NULL ){
Byte * bytes = (byte *) P;
Cplex * pnext = p-> pnext;
Delete [] bytes;
P = pnext;
}
}
Now let's use an instance to look at the actual memory action in the release version to allocate 10000 cstring arrays containing the "abcdefghijklmnopqrstuvwxyz" String
Cstring * strarray [10000]; for (Int = 0; I <10000; I ++)
Strarray [I] = new cstring ("abcdefghijklmnopqrstuvwxyz"); // because the string is smaller than 64, _ afxalloc64: alloc; _ afxalloc64 is defined in strcore. cpp as follows:
Afx_static cfixedalloc _ afxalloc64 (round4 (65 * sizeof (tchar) + sizeof (cstringdata); sizeof (tchar) = 1 in ANSI
Sizeof (cstrgindata) = 12;
65 * sizeof (tchar) + sizeof (cstringdata) = 77; Define round4 and round it to a multiple of 4,
# Define round (x, y) (x) + (Y-1 ))&~ (Y-1 ))
# Define round4 (x) round (x, 4)
So
_ Afxalloc64 (round4 (65 * sizeof (tchar) + sizeof (cstringdata) actually
The grand scale was finally launched
Extern cfixedalloc _ afxalloc64 (80, 64 );
Allocate pool size in cplex
Sizeof (cplex) + Nmax * cbelement = 4 + 80*64 = 5124 byte. Because 10000 is not an integer multiple of 64 = 157 pools need to be allocated
Actually allocated memory = 157*5124 = 804468 byte = 804kb. Release the cstring object
For (Int = 0; I <10000; I ++)
Delete strarray [I];
In this case, cstring calls _ afxalloc64.free. the implementation of cfixedalloc: Free shows that the memory is not actually released at this time, but the block is re-added to the m_pnodefree linked list for use. because the cfixedalloc memory release operation is performed in the Destructor call, And _ afxalloc64 is defined as a global object. it can be called only when the program exits. therefore, cfixedalloc can only be added but cannot be recycled before the end of the program. if we re-allocate 10000 strings> 64 <= 128 of the cstring object, the memory usage of _ afxalloc64 remains, while that of _ afxalloc128 is 157*(4 + 144*64) = 157*9220 = 1447540 = 1.44754mb. The memory usage is 1.44754 MB + 804kb = 2.252008mb. compared with char * object: char * charray [10000]; allocate "abcdefghijklmnopqrstuvwxyz". The actual memory size is 27*10000 = 128 kb. After the memory is released, it is recycled. The memory size is 10000*129 = 1.29mb. after the memory is released, it is recycled.

Conclusion:
The cstring in vc6 uses the memory pool technology to improve the performance of the new and delete small memory and the heap fragmentation problem, and then generates a memory leak that is not a memory leak. In fact, the cstring problem in vc5 and vc6 is caused by the fact that C ++ adopts the new and delete rules to manage the memory. In vc7, The cstring still returns to the C method.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.