XSLT存档  

不及格的程序员-八神

 查看分类:  ASP.NET XML/XSLT JavaScripT   我的MSN空间Blog

对标题给出一个简而言之的结论:MFC经过几次的效能更新的版本,修复一些问题还会产生另一个问题

Realse版本的CString保留了所有512字节以下申请字符串的缓冲区,并未释放,说是为了减少内存碎片增加性能。

Struct
{
    CStrng title;
    int a;
    ....
}IoriStruct

样例结构如上,其余省略,运行问题与无问题代码说明【版权:不及格的程序员-八神

CString title = "this is a title";
for(i=0;i<9999;i++)
{
  IoriStruct *temp = new IoriStruct();
  temp->title = "this is a title"; //这样里引用上面的title是没有问题的,成员变量titlle字段类型换成std::string也没有问题,但是当直接在这里赋值“this is a thitle”常量并且在release模式就会有问题了,这个字符串会在内存里生成好多。 
}
...
delete 上面生成的结构代码省略;

程序在debug模式下运行后,结构占居空间已经不存在,内存被释放feee添充。【版权:不及格的程序员-八神

  

--------------CString内存占用问题Release模式运行结果----------------- 

程序运行之后,离开字符串变量范转后,内存里大量字符串存留,占居空间。【版权:不及格的程序员-八神

 

Windbg观察内存状态, 28大小的为IoriStruct, 1404的为与之对应的CString成员变量

结构大小

 当结构被 delete 后,结构的内存空间释放后已经被feee添充,可成员变量指向的内存区仍占用内存。

 调试版CRT new 关键源码

LISTROWINFO *list = new LISTROWINFO;
void* AFX_CDECL operator new(size_t nSize, LPCSTR lpszFileName, int nLine)
{
    return ::operator new(nSize, _NORMAL_BLOCK, lpszFileName, nLine);
}
void * __cdecl _nh_malloc_dbg (
        size_t nSize,
        int nhFlag,
        int nBlockUse,
        const char * szFileName,
        int nLine
        )
{
        void * pvBlk;
        for (;;)
        {
#ifdef _MT
            /* lock the heap
             */
            _mlock(_HEAP_LOCK);
            __try {
#endif  /* _MT */

            /* do the allocation
             */
            pvBlk = _heap_alloc_dbg(nSize, nBlockUse, szFileName, nLine);
#ifdef _MT
            }
            __finally {
                /* unlock the heap
                 */
                _munlock(_HEAP_LOCK);
            }
#endif  /* _MT */
            if (pvBlk || nhFlag == 0)
                return pvBlk;

            /* call installed new handler */
            if (!_callnewh(nSize))
                return NULL;
            /* new handler was successful -- try to allocate again */
        }
}
void * __cdecl _heap_alloc_dbg(
        size_t nSize,
        int nBlockUse,
        const char * szFileName,
        int nLine
        )
{
        long lRequest;
        size_t blockSize;
        int fIgnore = FALSE;
        _CrtMemBlockHeader * pHead;
        /* verify heap before allocation */
        if (_crtDbgFlag & _CRTDBG_CHECK_ALWAYS_DF)
            _ASSERTE(_CrtCheckMemory());
        lRequest = _lRequestCurr;

        /* break into debugger at specific memory allocation */
        if (lRequest == _crtBreakAlloc)
            _CrtDbgBreak();
        /* forced failure */
        if (!(*_pfnAllocHook)(_HOOK_ALLOC, NULL, nSize, nBlockUse, lRequest, szFileName, nLine))
        {
            if (szFileName)
                _RPT2(_CRT_WARN, "Client hook allocation failure at file %hs line %d.\n",
                    szFileName, nLine);
            else
                _RPT0(_CRT_WARN, "Client hook allocation failure.\n");

            return NULL;
        }
        /* cannot ignore CRT allocations */
        if (_BLOCK_TYPE(nBlockUse) != _CRT_BLOCK &&
            !(_crtDbgFlag & _CRTDBG_ALLOC_MEM_DF))
            fIgnore = TRUE;
        /* Diagnostic memory allocation from this point on */
        if (nSize > (size_t)_HEAP_MAXREQ ||
            nSize + nNoMansLandSize + sizeof(_CrtMemBlockHeader) > (size_t)_HEAP_MAXREQ)
        {
            _RPT1(_CRT_ERROR, "Invalid allocation size: %u bytes.\n", nSize);
            return NULL;
        }
        if (!_BLOCK_TYPE_IS_VALID(nBlockUse))
        {
            _RPT0(_CRT_ERROR, "Error: memory allocation: bad memory block type.\n");
        }
        blockSize = sizeof(_CrtMemBlockHeader) + nSize + nNoMansLandSize;
#ifndef WINHEAP
        /* round requested size */
        blockSize = _ROUND2(blockSize, _GRANULARITY);
#endif  /* WINHEAP */
        pHead = (_CrtMemBlockHeader *)_heap_alloc_base(blockSize);//具体申请多少内存 userSize
        if (pHead == NULL)
            return NULL;
        /* commit allocation */
        ++_lRequestCurr;
        if (fIgnore)
        {
            pHead->pBlockHeaderNext = NULL;
            pHead->pBlockHeaderPrev = NULL;
            pHead->szFileName = NULL;
            pHead->nLine = IGNORE_LINE;
            pHead->nDataSize = nSize;
            pHead->nBlockUse = _IGNORE_BLOCK;
            pHead->lRequest = IGNORE_REQ;
        }
        else {
            /* keep track of total amount of memory allocated */
            _lTotalAlloc += nSize;
            _lCurAlloc += nSize;

            if (_lCurAlloc > _lMaxAlloc)
                _lMaxAlloc = _lCurAlloc;

            if (_pFirstBlock)
                _pFirstBlock->pBlockHeaderPrev = pHead;
            else
                _pLastBlock = pHead;

            pHead->pBlockHeaderNext = _pFirstBlock;
            pHead->pBlockHeaderPrev = NULL;
            pHead->szFileName = (char *)szFileName;
            pHead->nLine = nLine;
            pHead->nDataSize = nSize;
            pHead->nBlockUse = nBlockUse;
            pHead->lRequest = lRequest;

            /* link blocks together */
            _pFirstBlock = pHead;
        }

        /* fill in gap before and after real block */
        memset((void *)pHead->gap, _bNoMansLandFill, nNoMansLandSize);
        memset((void *)(pbData(pHead) + nSize), _bNoMansLandFill, nNoMansLandSize);

        /* fill data with silly value (but non-zero) */
        memset((void *)pbData(pHead), _bCleanLandFill, nSize);

        return (void *)pbData(pHead);
}

传入0x70+0n32+4 = 0x94 blocksize,  return 0xa0; 这个a0就是 -flt s a0 的尺寸由来,下面图示中有A0尺寸。

void * __cdecl _heap_alloc_base (size_t size)
{
#ifdef WINHEAP
        void * pvReturn;
#else  /* WINHEAP */
        _PBLKDESC pdesc;
        _PBLKDESC pdesc2;
#endif  /* WINHEAP */

#ifdef WINHEAP
        if ( __active_heap == __V6_HEAP )
        {
            if ( size <= __sbh_threshold )
            {
#ifdef _MT
                _mlock( _HEAP_LOCK );
                __try {
#endif  /* _MT */
                pvReturn = __sbh_alloc_block(size);
#ifdef _MT
                }
                __finally {
                    _munlock( _HEAP_LOCK );
                }
#endif  /* _MT */
                if (pvReturn)
                    return pvReturn;
            }
        }
        else if ( __active_heap == __V5_HEAP )
        {
            /* round up to the nearest paragraph */
            if ( size )
                size = (size + _OLD_PARASIZE - 1) & ~(_OLD_PARASIZE - 1);
            else
                size = _OLD_PARASIZE;
            if ( size  <= __old_sbh_threshold ) {
#ifdef _MT
                _mlock(_HEAP_LOCK);
                __try {
#endif  /* _MT */
                pvReturn = __old_sbh_alloc_block(size >> _OLD_PARASHIFT);
#ifdef _MT
                }
                __finally {
                    _munlock(_HEAP_LOCK);
                }
#endif  /* _MT */
                if ( pvReturn != NULL )
                    return pvReturn;
            }

            return HeapAlloc( _crtheap, 0, size );
        }
        if (size == 0)
            size = 1;
        size = (size + BYTES_PER_PARA - 1) & ~(BYTES_PER_PARA - 1);
        return HeapAlloc(_crtheap, 0, size);
}
#else  /* WINHEAP */
        /* try to find a big enough free block
         */
        if ( (pdesc = _heap_search(size)) == NULL )
        {
            if ( _heap_grow(size) != -1 )
            {
                /* try finding a big enough free block again. the
                 * success of the call to _heap_grow should guarantee
                 * it, but...
                 */
                if ( (pdesc = _heap_search(size)) == NULL )
                {
                    /* something unexpected, and very bad, has
                     * happened. abort!
                     */
                    _heap_abort();
                }
            }
            else
                return NULL;
        }
        /* carve the block into two pieces (if necessary). the first piece
         * shall be of the exact requested size, marked inuse and returned to
         * the caller. the leftover piece is to be marked free.
         */
        if ( _BLKSIZE(pdesc) != size ) {
            /* split up the block and free the leftover piece back to
             * the heap
             */
            if ( (pdesc2 = _heap_split_block(pdesc, size)) != NULL )
                _SET_FREE(pdesc2);
        }
        /* mark pdesc inuse
         */
        _SET_INUSE(pdesc);
        /* check proverdesc and reset, if necessary
         */
        _heap_desc.proverdesc = pdesc->pnextdesc;

        return( (void *)((char *)_ADDRESS(pdesc) + _HDRSIZE) );
}
/***
*winheap.h - Private include file for winheap directory.
*
*       Copyright (c) 1988-1998, Microsoft Corporation. All rights reserved.
*
*Purpose:
*       Contains information needed by the C library heap code.
*
*       [Internal]
*
****/
#if _MSC_VER > 1000
#pragma once
#endif  /* _MSC_VER > 1000 */
#ifndef _INC_WINHEAP
#define _INC_WINHEAP
#ifndef _CRTBLD
/*
 * This is an internal C runtime header file. It is used when building
 * the C runtimes only. It is not to be used as a public header file.
 */
#error ERROR: Use of C runtime library internal header file.
#endif  /* _CRTBLD */
#ifdef __cplusplus
extern "C" {
#endif  /* __cplusplus */
#include <windows.h>
//  Declarations and definitions for the multiple heap scheme (VC++ 6.1)
//  Heap-selection constants
#define __SYSTEM_HEAP           1
#define __V5_HEAP               2
#define __V6_HEAP               3
#define __HEAP_ENV_STRING       "__MSVCRT_HEAP_SELECT"
#define __GLOBAL_HEAP_SELECTOR  "__GLOBAL_HEAP_SELECTED"
//  Heap-selection global variable
extern int  __active_heap;
//  Linker info for heap selection
typedef struct {
    union {
        DWORD   dw;
        struct {
            BYTE    bverMajor;
            BYTE    bverMinor;
        };
    };
}   LinkerVersion;
extern void __cdecl _GetLinkerVersion(LinkerVersion * plv);
//  Definitions, declarations and prototypes for the small-block heap (VC++ 6.0)
#define BYTES_PER_PARA      16
#define DWORDS_PER_PARA     4
#define PARAS_PER_PAGE      256     //  tunable value
#define PAGES_PER_GROUP     8       //  tunable value
#define GROUPS_PER_REGION   32      //  tunable value (max 32)
#define BYTES_PER_PAGE      (BYTES_PER_PARA * PARAS_PER_PAGE)
#define BYTES_PER_GROUP     (BYTES_PER_PAGE * PAGES_PER_GROUP)
#define BYTES_PER_REGION    (BYTES_PER_GROUP * GROUPS_PER_REGION)
#define ENTRY_OFFSET        0x0000000cL     //  offset of entry in para
#define OVERHEAD_PER_PAGE   0x00000010L     //  sixteen bytes of overhead
#define MAX_FREE_ENTRY_SIZE (BYTES_PER_PAGE - OVERHEAD_PER_PAGE)
#define BITV_COMMIT_INIT    (((1 << GROUPS_PER_REGION) - 1) << \
                                            (32 - GROUPS_PER_REGION))
#define MAX_ALLOC_DATA_SIZE     0x3f8
#define MAX_ALLOC_ENTRY_SIZE    (MAX_ALLOC_DATA_SIZE + 0x8)
typedef unsigned int    BITVEC;
typedef struct tagListHead
{
    struct tagEntry *   pEntryNext;
    struct tagEntry *   pEntryPrev;
}
LISTHEAD, *PLISTHEAD;
typedef struct tagEntry
{
    int                 sizeFront;
    struct tagEntry *   pEntryNext;
    struct tagEntry *   pEntryPrev;
}
ENTRY, *PENTRY;
typedef struct tagEntryEnd
{
    int                 sizeBack;
}
ENTRYEND, *PENTRYEND;
typedef struct tagGroup
{
    int                 cntEntries;
    struct tagListHead  listHead[64];
}
GROUP, *PGROUP;
typedef struct tagRegion
{
    int                 indGroupUse;
    char                cntRegionSize[64];
    BITVEC              bitvGroupHi[GROUPS_PER_REGION];
    BITVEC              bitvGroupLo[GROUPS_PER_REGION];
    struct tagGroup     grpHeadList[GROUPS_PER_REGION];
}
REGION, *PREGION;
typedef struct tagHeader
{
    BITVEC              bitvEntryHi;
    BITVEC              bitvEntryLo;
    BITVEC              bitvCommit;
    void *              pHeapData;
    struct tagRegion *  pRegion;
}
HEADER, *PHEADER;
extern  HANDLE _crtheap;
/*
 * Global variable declarations for the small-block heap.
 */
extern size_t   __sbh_threshold;

void * __cdecl  _nh_malloc(size_t, int);
void * __cdecl  _heap_alloc(size_t);
extern PHEADER  __sbh_pHeaderList;        //  pointer to list start
extern PHEADER  __sbh_pHeaderScan;        //  pointer to list rover
extern int      __sbh_sizeHeaderList;     //  allocated size of list
extern int      __sbh_cntHeaderList;      //  count of entries defined
extern PHEADER  __sbh_pHeaderDefer;
extern int      __sbh_indGroupDefer;
extern size_t  __cdecl _get_sb_threshold(void);
extern int     __cdecl _set_sb_threshold(size_t);
extern int     __cdecl _heap_init(int);
extern void    __cdecl _heap_term(void);
extern void *  __cdecl _malloc_base(size_t);
extern void *  __cdecl _nh_malloc_base(size_t, int);
extern void *  __cdecl _heap_alloc_base(size_t);
extern void    __cdecl _free_base(void *);
extern void *  __cdecl _realloc_base(void *, size_t);
extern void *  __cdecl _expand_base(void *, size_t);
extern void *  __cdecl _calloc_base(size_t, size_t);
extern size_t  __cdecl _msize_base(void *);
extern int     __cdecl __sbh_heap_init(size_t);
extern void *  __cdecl __sbh_alloc_block(int);
extern PHEADER __cdecl __sbh_alloc_new_region(void);
extern int     __cdecl __sbh_alloc_new_group(PHEADER);
extern PHEADER __cdecl __sbh_find_block(void *);
#ifdef _DEBUG
extern int     __cdecl __sbh_verify_block(PHEADER, void *);
#endif  /* _DEBUG */
extern void    __cdecl __sbh_free_block(PHEADER, void *);
extern int     __cdecl __sbh_resize_block(PHEADER, void *, int);
extern void    __cdecl __sbh_heapmin(void);
extern int     __cdecl __sbh_heap_check(void);
//  Definitions, declarations and prototypes for the old small-block heap
//  (shipped with VC++ 5.0)
#ifdef _M_ALPHA
#define _OLD_PAGESIZE   0x2000      //  one page
#else  /* _M_ALPHA */
#define _OLD_PAGESIZE   0x1000      //  one page
#endif  /* _M_ALPHA */
//  Constants and types used by the old small-block heap
#define _OLD_PARASIZE               0x10
#define _OLD_PARASHIFT              0x4
#ifdef _M_ALPHA
#define _OLD_PARAS_PER_PAGE         454
#define _OLD_PADDING_PER_PAGE       5
#define _OLD_PAGES_PER_REGION       512
#define _OLD_PAGES_PER_COMMITMENT   8
#else  /* _M_ALPHA */
#define _OLD_PARAS_PER_PAGE         240
#define _OLD_PADDING_PER_PAGE       7
#define _OLD_PAGES_PER_REGION       1024
#define _OLD_PAGES_PER_COMMITMENT   16
#endif  /* _M_ALPHA */
typedef char            __old_para_t[16];
#ifdef _M_ALPHA
typedef unsigned short  __old_page_map_t;
#else  /* _M_ALPHA */
typedef unsigned char   __old_page_map_t;
#endif  /* _M_ALPHA */
#define _OLD_FREE_PARA          (__old_page_map_t)(0)
#define _OLD_UNCOMMITTED_PAGE   (-1)
#define _OLD_NO_FAILED_ALLOC    (size_t)(_OLD_PARAS_PER_PAGE + 1)
//  Small-block heap page. The first four fields of the structure below are
//  descriptor for the page. That is, they hold information about allocations
//  in the page. The last field (typed as an array of paragraphs) is the
//  allocation area.
typedef struct __old_sbh_page_struct {
        __old_page_map_t *  p_starting_alloc_map;
        size_t              free_paras_at_start;
        __old_page_map_t    alloc_map[_OLD_PARAS_PER_PAGE + 1];
        __old_page_map_t    reserved[_OLD_PADDING_PER_PAGE];
        __old_para_t        alloc_blocks[_OLD_PARAS_PER_PAGE];
}       __old_sbh_page_t;

#define _OLD_NO_PAGES       (__old_sbh_page_t *)0xFFFFFFFF
//  Type used in small block region desciptor type (see below).
typedef struct {
        int     free_paras_in_page;
        size_t  last_failed_alloc;
}       __old_region_map_t;
//  Small-block heap region descriptor. Most often, the small-block heap
//  consists of a single region, described by the statically allocated
//  decriptor __small_block_heap (declared below).
struct __old_sbh_region_struct {
        struct __old_sbh_region_struct *p_next_region;
        struct __old_sbh_region_struct *p_prev_region;
        __old_region_map_t *            p_starting_region_map;
        __old_region_map_t *            p_first_uncommitted;
        __old_sbh_page_t *              p_pages_begin;
        __old_sbh_page_t *              p_pages_end;
        __old_region_map_t              region_map[_OLD_PAGES_PER_REGION + 1];
};

typedef struct __old_sbh_region_struct  __old_sbh_region_t;
//  Global variable declarations for the old small-block heap.
extern __old_sbh_region_t   __old_small_block_heap;
extern size_t               __old_sbh_threshold;
//  Prototypes for internal functions of the old small-block heap.
void *    __cdecl __old_sbh_alloc_block(size_t);
void *    __cdecl __old_sbh_alloc_block_from_page(__old_sbh_page_t *, size_t,
        size_t);
void      __cdecl __old_sbh_decommit_pages(int);
__old_page_map_t * __cdecl __old_sbh_find_block(void *, __old_sbh_region_t **,
        __old_sbh_page_t **);
void      __cdecl __old_sbh_free_block(__old_sbh_region_t *, __old_sbh_page_t *,
        __old_page_map_t *);
int       __cdecl __old_sbh_heap_check(void);
__old_sbh_region_t * __cdecl __old_sbh_new_region(void);
void      __cdecl __old_sbh_release_region(__old_sbh_region_t *);
int       __cdecl __old_sbh_resize_block(__old_sbh_region_t *,
        __old_sbh_page_t *, __old_page_map_t *, size_t);
#ifdef __cplusplus
}
#endif  /* __cplusplus */

#endif  /* _INC_WINHEAP */

 

 

 

 dataSize = 0x70

 

 

 

 

 

flt size = a0, address:2255e70

 

//vc98/crt/src/dbgint.h

#define nNoMansLandSize 4

typedef struct _CrtMemBlockHeader
{
        struct _CrtMemBlockHeader * pBlockHeaderNext;
        struct _CrtMemBlockHeader * pBlockHeaderPrev;
        char *                      szFileName;
        int                         nLine;
        size_t                      nDataSize;
        int                         nBlockUse;
        long                        lRequest;
        unsigned char               gap[nNoMansLandSize];
        /* followed by:
         *  unsigned char           data[nDataSize];
         *  unsigned char           anotherGap[nNoMansLandSize];
         */
} _CrtMemBlockHeader;

#define pbData(pblock) ((unsigned char *)((_CrtMemBlockHeader *)pblock + 1)) //类型指针+1 == 地址+32 直接指向_ListRowInfo
#define pHdr(pbData) (((_CrtMemBlockHeader *)pbData)-1)

 

0:000> dt _CrtMemBlockHeader 02255e70 ...
MSVCRTD!_CrtMemBlockHeader
+0x000 pBlockHeaderNext :
+0x004 pBlockHeaderPrev :
+0x008 szFileName :
+0x00c nLine : 0n73
+0x010 nDataSize : 0x70
+0x014 nBlockUse : 0n1
+0x018 lRequest : 0n87
+0x01c gap : [4] "???"

0:000> ? 02255e90 - 02255e70
Evaluate expression: 32 = 00000020

0:000> ?? sizeof(_LISTROWINFO)
unsigned int 0x70

0:000> ? 02255e90 + 70
Evaluate expression: 36003584 = 02255f00

? 02255e70 +A0 
Evaluate expression: 36003600 = 02255f10

02255e68 2cdc0c79
02255e6c 180071c5
02255e70 02255de8
02255e74 02255f28
02255e78 004176a8 TestMFC!THIS_FILE
02255e7c 00000049
02255e80 00000070
02255e84 00000001
02255e88 00000057
02255e8c fdfdfdfd
02255e90 00416540 TestMFC!_LISTROWINFO::`vftable'
02255e94 cdcdcdcd
02255e98 cdcdcdcd
02255e9c 5f4aef8c MFC42D!CStringArray::`vftable'
02255ea0 00000000
02255ea4 00000000
02255ea8 00000000
02255eac 00000000
02255eb0 5f4d0b14 MFC42D!_afxInitData+0xc
02255eb4 cdcdcdcd
02255eb8 cdcdcdcd
02255ebc cdcdcdcd
02255ec0 cdcdcdcd
02255ec4 cdcdcdcd
02255ec8 5f4d0b14 MFC42D!_afxInitData+0xc
02255ecc 02255f54
02255ed0 cdcdcdcd
02255ed4 cdcdcdcd
02255ed8 00000000
02255edc 00000000
02255ee0 00000000
02255ee4 cdcdcdcd
02255ee8 cdcdcdcd
02255eec cdcdcdcd
02255ef0 cdcdcdcd
02255ef4 cdcdcdcd
02255ef8 00000064
02255efc 5f4d0b14 MFC42D!_afxInitData+0xc
02255f00 fdfdfdfd
02255f04 baadf00d
02255f08 baadf00d
02255f0c baadf00d
02255f10 abababab
02255f14 abababab
02255f18 00000000
02255f1c 00000000
02255f20 30dc0c65
02255f24 180071c3
02255f28 02255e70
02255f2c 02251390
02255f30 5f4d0b18 MFC42D!THIS_FILE

 

Release版:直接就是0x70没有附加内存

0:000> !heap -s
NtGlobalFlag enables following debugging aids for new heaps:
    tail checking
    free checking
    validate parameters
LFH Key                   : 0x8ebb7717
Termination on corruption : DISABLED
  Heap     Flags   Reserv  Commit  Virt   Free  List   UCR  Virt  Lock  Fast 
                    (k)     (k)    (k)     (k) length      blocks cont. heap 
-----------------------------------------------------------------------------
004d0000 40000062    1020    456   1020    105    50     1    0      0      
00820000 40001062    3124   2196   3124      5    12     3    0      0      
02470000 40001062      60     16     60      2    12     1    0      0      
02440000 40001062      60     20     60      6     2     1    0      0      
-----------------------------------------------------------------------------
0:000> !heap -stat -h 00820000 
 heap @ 00820000
group-by: TOTSIZE max-display: 20
    size     #blocks     total     ( %) (percent of total busy bytes)
    70 2711 - 111770  (56.23)
    1404 9d - c4674  (40.39)
0:000> !heap -flt s70
    _HEAP @ 4d0000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        0051d158 0011 0011  [00]   0051d160    00070 - (busy)
        0051dc28 0011 0011  [00]   0051dc30    00070 - (busy)
        00520448 0011 0011  [00]   00520450    00070 - (busy)
        005270f0 0011 0011  [00]   005270f8    00070 - (busy)
    _HEAP @ 820000
        00821af8 0011 0011  [00]   00821b00    00070 - (busy)
          TestMFC!_LISTROWINFO::`vftable'
        00821b80 0011 0011  [00]   00821b88    00070 - (busy)
          TestMFC!_LISTROWINFO::`vftable'
        00821c08 0011 0011  [00]   00821c10    00070 - (busy)

 

->? 00821b00 +70
Evaluate expression: 8526704 = 00821b70

->dds 00821b00    
00821b00  00403728 TestMFC!_LISTROWINFO::`vftable'
00821b04  baadf00d
00821b08  baadf00d
00821b0c  751728e8 MFC42!CStringArray::`vftable'
00821b10  00000000
00821b14  00000000
00821b18  00000000
00821b1c  00000000
00821b20  7526fb24 MFC42!_afxInitData+0xc
00821b24  baadf00d
00821b28  baadf00d
00821b2c  baadf00d
00821b30  baadf00d
00821b34  baadf00d
00821b38  7526fb24 MFC42!_afxInitData+0xc
00821b3c  00824ff8 //stroldtext 成员; da 00824ff8 -> '...abc'
00821b40  baadf00d
00821b44  baadf00d
00821b48  00000000
00821b4c  00000000
00821b50  00000000
00821b54  baadf00d
00821b58  baadf00d
00821b5c  baadf00d
00821b60  baadf00d
00821b64  baadf00d
00821b68  00000064 //100
00821b6c  7526fb24 MFC42!_afxInitData+0xc //最后一个CString成员
00821b70  abababab
00821b74  abababab
00821b78  00000000
00821b7c  00000000

 


 

  下面是网上搜到的相关问题,它认为CString有bug,也是人之常情。


 

VC++ 6.0中CArray中保存大量对象时内存无法释放的问题,请各位指点 RRS feed

  • 问题

  • 复现条件:

    1、编译环境:VC++ 6.0

    2、以release方式编译,全部使用默认的编译选项和参数,并且不使用调试器执行该应用程序

    3、在数组中存放超过100万个对象

    执行程序后,在我的电脑上,接近有85M的内存无法自动释放。

    有哪位能够帮忙解释并解决这个问题吗?

    btw:受限于历史项目代码,我的应用程序开发环境无法迁移到更新的VisualStudio开发环境,因此不要建议我升级。谢谢。 

    #include "afxtempl.h"

    long int g_cCount = 0; // 记录构造函数调用次数
    long int g_dCount = 0; // 记录析构函数调用次数

    class CMyTest
    {
    public:
    CString m_str;


    CMyTest()
    {
    m_str = "test string";

    g_cCount++;
    }


    ~CMyTest()
    {
    g_dCount++;
    }

    };

    typedef CArray<CMyTest,CMyTest&> CArrayTest;



    void Test()
    {
    g_cCount = 0;
    g_dCount = 0;

    CArrayTest testArray;

    int count = 1000000; // 一百万个对象
    for(int i =0;i < count; i++ )
    {
    CMyTest testObj;
    testObj.m_str = "test string";

    testArray.Add(testObj);
    }

    testArray.RemoveAll();
    testArray.FreeExtra();
    }

    void CTestMemDlg::OnOK() 
    {
    Test();

    CString strInfo;
    strInfo.Format("Object construction: %d  destruction: %d \r\n",g_cCount,g_dCount);
    AfxMessageBox("finish\r\n"+strInfo);
    }

    2016年6月5日 14:02
  •  

    根据CArray Class的官方文档中的介绍, 使用数组之前,使用setSize来设置它的大小和分配内存。如果你不使用的setSize,将元素添加到数组将导致它重新分配内存并复制。频繁的重新分配内存和复制是低效的,而且容易产生内存碎片。因此,请在使用数组前,使用setSize给数组分配内存。

    Best Regards,

    Sera Yu


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.

    • 已编辑 Baron Bi 2016年6月6日 5:52
  •  

    按照你的说法,我也尝试了先用SetSize来设置数据的总大小,并用SetAt(而不用Add)来添加对象到数组中。

    但是,没有任何效果。

    2016年6月6日 13:17
  •  

    我继续做了各种实验,发现问题并不是仅仅在CArray上出现。

    在下面的例子中,我仅仅只是创建了若干个CString对象,然后再逐一将其删除。程序执行完之后,同样大概有86M的内存无法释放。

    我彻底懵了。这到底是怎么回事呢?

    一百万个对象并不是必须的,只不过是占用内存比较明显而已。一千或者一万个对象都会存在同样的内存无法完全释放的问题。

    void TestXXX()
    {
    int count = 1000000;

    CString** pStrArray = new CString*[count];

    for( int i =0; i< count; i++)
    {
    CString* pStr = new CString();
    pStr->Format("some string %d",i);

    pStrArray[i] = pStr;
    }


    for( int j =0; j< count; j++)
    {
    CString* pStr = pStrArray[j];

    delete pStr;
    }

    delete []pStrArray;

    }

     

  •  

    使用我上面的示例代码,只需要运行一次,就会明显看到内存的增大,运行完之后内存不会立即释放。

    我尝试将CArray、CString都使用std::vector和std::string 替代之后,运行程序之后内存会立即释放。

    现在,我严重怀疑VC++ 6.0中CString类的内存管理机制有一定的问题。

 
posted on 2023-03-04 21:42  不及格的程序员-八神  阅读(119)  评论(0编辑  收藏  举报