为啥 Visual Studio CRT 内存报告显示 CRT 块

Posted

技术标签:

【中文标题】为啥 Visual Studio CRT 内存报告显示 CRT 块【英文标题】:Why does Visual Studio CRT memory report show CRT blocks为什么 Visual Studio CRT 内存报告显示 CRT 块 【发布时间】:2015-01-23 04:03:09 【问题描述】:

我正在练习使用 CRT 库来查找内存泄漏。我写了一些这样的代码:

#define _CRTDBG_MAP_ALLOC
#include <stdio.h>
#include <stdlib.h>
#include <crtdbg.h>

typedef struct NodeLL 
    int value;
    struct NodeLL *next;
 Node;

void printLL(Node *pHead) 
    int i=0;
    while(pHead) 
        printf("%d\n", pHead->value);
        i++;
        pHead = pHead->next;
    


Node * addNode(Node *pHead, int value) 
    Node *pNew, *pLL;
    pNew = (Node *)malloc(sizeof(Node));
    pNew->value = value;
    pNew->next = NULL;
    if(!pHead) 
        pHead = pNew;
    
    else 
        pLL = pHead;
        while(pLL->next) 
            pLL = pLL->next;
        pLL->next = pNew;
    

    return pHead;


void deleteNodes(Node *pHead) 
    Node *pLL;
    int i=0;
    while(pHead) 
        printf("deleting node %d, value is %d\n", i, pHead->value); 
        i++;
        pLL = pHead->next;
        free(pHead);
        pHead = pLL;
    



Node * removeDups(Node *pHead) 
    if (!pHead)
        return NULL;
    Node *pNode2, *pPrev;
    Node *pNode = pHead;
    while(pNode) 
        pPrev = pNode;
        pNode2 = pNode->next; 
        while(pNode2) 
            if(pNode2->value == pNode->value) 
                pPrev->next = pNode2->next;
                free(pNode2);
                pNode2 = pPrev->next;
            
            else 
                pPrev = pNode2;
                pNode2 = pNode2->next;
            
        
        pNode = pNode->next;
    
    return pHead;


int main() 

    _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG);
    //_CrtSetBreakAlloc(71);   // used to break at the second malloc

    _CrtMemState s1, s2, s3;

    // take a snap shot of memory before allocating memory
    _CrtMemCheckpoint(&s1);

    int NodeNum, i, j, value;
    Node *pHead = NULL;

    printf("How many nodes in the linked list?");
    scanf("%d", &NodeNum); 
    for (i=0; i<NodeNum; i++) 
        printf("Please enter Node %d value:", i);
        scanf("%d", &value);
        pHead = addNode(pHead, value);
    


    printLL(pHead);
    printf("remove duplicates\n");
    pHead = removeDups(pHead);
    printLL(pHead);
    // clean up
    //deleteNodes(pHead);

    _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG);
    _CrtDumpMemoryLeaks();


    // take a snap shot of memory after allocating memory
    _CrtMemCheckpoint(&s2);

    if(_CrtMemDifference(&s3, &s1, &s2) ) 
        _CrtMemDumpStatistics(&s3);

    return 0;

我得到以下输出:

Detected memory leaks!

Dumping objects -> ...

\2_1_removedupll\removedupsll.cpp(23) : 72 normal block at 0x00701570, 8 bytes long.
 Data: <        > 03 00 00 00 00 00 00 00 

\2_1_removedupll\removedupsll.cpp(23) : 71 normal block at 0x00701528, 8 bytes long.
 Data: <    p p > 02 00 00 00 70 15 70 00 

\2_1_removedupll\removedupsll.cpp(23) : 70 normal block at 0x007014E0, 8 bytes long.
 Data: <    ( p > 01 00 00 00 28 15 70 00 

Object dump complete.

0 bytes in 0 Free Blocks.

24 bytes in 3 Normal Blocks.

*4096 bytes in 1 CRT Blocks.*

0 bytes in 0 Ignore Blocks.

0 bytes in 0 Client Blocks.

Largest number used: 3870 bytes.

Total allocations: 4120 bytes.

它发现泄漏了 24 字节的正常块。我期望。但是 1 个 CRT 块中的 4096 字节是什么?据微软称:

CRT 库分配一个 CRT 块供自己使用。 CRT 库处理这些块的释放。因此,除非出现严重错误,例如 CRT 库已损坏,否则您不太可能在内存泄漏报告中看到这些内容。

我应该忽略这 4096 个字节吗?谢谢。

【问题讨论】:

【参考方案1】:

这 4,096 字节分配是 stdout 的临时缓冲区,在您第一次调用 printf 时分配。因为您第一次调用printf 是在您的两个内存检查点之间,所以它显示为两个检查点之间的差异。如果您在第一个内存检查点之前添加对printf 的调用,则此 4,096 字节分配将不会出现在差异中。

当 CRT 正常终止时,此缓冲区被释放。

【讨论】:

【参考方案2】:

看来确实有一些漏洞。我已经用Deleaker 检查了你的代码,看看我得到了什么:

link to the image

另外,如果我在 free() 行设置断点,在输入两个相同值的情况下我永远不会打到那里。

如果我输入两个不同的值,我会点击一次 free()(在 removeDups() 函数中)。只有一次。

显然代码出了点问题!最后不需要调用 deleteNodes() 吗?

【讨论】:

嗨,Artem,感谢您帮我检查。是的,有泄漏。我故意没有释放列表来查看内存泄漏检查是如何工作的。我不知道我是否应该担心 4096 CRT 块。就像下面的 Anrsimha 说的,我可以忽略它,因为它是由 Visual Studio 管理的。 @Amber,不!你不能。这是一个真正的泄漏,您必须释放此内存。当然,在这样简单的项目中,这可能不是什么大问题,但在真正的项目中,内存泄漏是个大问题:内存不足和应用程序崩溃:)【参考方案3】:

是的,可以安全地忽略 CRT 块。分配不是由你的代码完成的,所以你不必理会它

【讨论】:

谢谢。我没有足够的声望来支持它。

以上是关于为啥 Visual Studio CRT 内存报告显示 CRT 块的主要内容,如果未能解决你的问题,请参考以下文章

为啥 cl.exe(Visual Studio 编译器)无法使用 CMake(错误报告)编译项目?

为啥“查看堆”结果与 Visual Studio 中的“进程内存使用”不匹配

为啥 CRT 和 VS 内存分析的结果如此不同?

我的程序使用多少RAM?内存分析报告Visual Studio

在 Visual Studio 中检查内存转储时匿名命名空间中的符号

为啥在安装Visual Studio 2005之后,开机时"SVCHOST.EXE"进程占用CPU很高?且内存消耗将近100MB!?