• c/c++内存泄露的检测方法


    此文内容摘自

    https://zhuanlan.zhihu.com/p/22664202

    作为   从零开始的 JSON 库教程(三):解析字符串解答篇  的笔记

    1A. Windows 下的内存泄漏检测方法

    在 Windows 下,可使用 Visual C++ 的 C Runtime Library(CRT) 检测内存泄漏

    首先,我们在两个 .c 文件首行插入这一段代码:

    #ifdef _WINDOWS
    #define _CRTDBG_MAP_ALLOC
    #include <crtdbg.h>
    #endif
    

    并在 main() 开始位置插入:

    int main() {
    #ifdef _WINDOWS
        _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
    #endif
    

    在 Debug 配置下按 F5 生成、开始调试程序,没有任何异样。

    然后,我们删去 lept_set_boolean() 中的 lept_free(v):

    void lept_set_boolean(lept_value* v, int b) {
        /* lept_free(v); */
        v->type = b ? LEPT_TRUE : LEPT_FALSE;
    }
    

    再次按 F5 生成、开始调试程序,在输出会看到内存泄漏信息:

    Detected memory leaks!
    Dumping objects ->
    C:GitHubjson-tutorial	utorial03_answerleptjson.c(212) : {79} normal block at 0x013D9868, 2 bytes long.
     Data: <a > 61 00 
    Object dump complete.
    

    这正是我们在单元测试中,先设置字符串,然后设布尔值时没释放字符串所分配的内存。比较麻烦的是,它没有显示调用堆栈。从输出信息中 ... {79} ... 我们知道是第 79 次分配的内存做成问题,我们可以加上 _CrtSetBreakAlloc(79); 来调试,那么它便会在第 79 次时中断于分配调用的位置,那时候就能从调用堆栈去找出来龙去脉。

    1B. Linux/OSX 下的内存泄漏检测方法

    在 Linux、OS X 下,我们可以使用 valgrind 工具(用 apt-get install valgrind、 brew install valgrind)。我们完全不用修改代码,只要在命令行执行:

    $ valgrind --leak-check=full  ./leptjson_test
    ==22078== Memcheck, a memory error detector
    ==22078== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
    ==22078== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
    ==22078== Command: ./leptjson_test
    ==22078== 
    --22078-- run: /usr/bin/dsymutil "./leptjson_test"
    160/160 (100.00%) passed
    ==22078== 
    ==22078== HEAP SUMMARY:
    ==22078==     in use at exit: 27,728 bytes in 209 blocks
    ==22078==   total heap usage: 301 allocs, 92 frees, 34,966 bytes allocated
    ==22078== 
    ==22078== 2 bytes in 1 blocks are definitely lost in loss record 1 of 79
    ==22078==    at 0x100012EBB: malloc (in /usr/local/Cellar/valgrind/3.11.0/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
    ==22078==    by 0x100008F36: lept_set_string (leptjson.c:208)
    ==22078==    by 0x100008415: test_access_boolean (test.c:187)
    ==22078==    by 0x100001849: test_parse (test.c:229)
    ==22078==    by 0x1000017A3: main (test.c:235)
    ==22078== 
    ...
    

    它发现了在 test_access_boolean() 中,由 lept_set_string() 分配的 2 个字节("a")泄漏了。

    Valgrind 还有很多功能,例如可以发现未初始化变量。我们若在应用程序或测试程序中,忘了调用 lept_init(&v),那么v.type 的值没被初始化,其值是不确定的(indeterministic),一些函数如果读取那个值就会出现问题:

    static void test_access_boolean() {
        lept_value v;
        /* lept_init(&v); */
        lept_set_string(&v, "a", 1);
        ...
    }
    

    这种错误有时候测试时能正确运行(刚好 v.type 被设为 0),使我们误以为程序正确,而在发布后一些机器上却可能崩溃。这种误以为正确的假像是很危险的,我们可利用 valgrind 能自动测出来:

    $ valgrind --leak-check=full  ./leptjson_test
    ...
    ==22174== Conditional jump or move depends on uninitialised value(s)
    ==22174==    at 0x100008B5D: lept_free (leptjson.c:164)
    ==22174==    by 0x100008F26: lept_set_string (leptjson.c:207)
    ==22174==    by 0x1000083FE: test_access_boolean (test.c:187)
    ==22174==    by 0x100001839: test_parse (test.c:229)
    ==22174==    by 0x100001793: main (test.c:235)
    ==22174== 
    

    它发现 lept_free() 中依靠了一个未初始化的值来跳转,就是 v.type,而错误是沿自 test_access_boolean()。

    编写单元测试时,应考虑哪些执行次序会有机会出错,例如内存相关的错误。然后我们可以利用 TDD 的步骤,先令测试失败(以内存工具检测),修正代码,再确认测试是否成功。

  • 相关阅读:
    管理中的“变”与“不变”
    软件项目需求分析与管理的十大疑问
    小商家也要有O2O思维
    互联网时代CIO生存法则
    浅谈项目经理与部门经理之间的关系
    沃尔玛:“最后一公里”的致命伤
    大数据分析案例:永远别忘记天气这个变量
    IT项目中的6类知识转移
    C
    linu入门
  • 原文地址:https://www.cnblogs.com/gk2017/p/7152088.html
Copyright © 2020-2023  润新知