此文内容摘自

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:\GitHub\json-tutorial\tutorial03_answer\leptjson.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 的步骤,先令测试失败(以内存工具检测),修正代码,再确认测试是否成功。

c/c++内存泄露的检测方法的更多相关文章

  1. C++中内存泄漏的检测方法介绍

    C++中内存泄漏的检测方法介绍 首先我们需要知道程序有没有内存泄露,然后定位到底是哪行代码出现内存泄露了,这样才能将其修复. 最简单的方法当然是借助于专业的检测工具,比较有名如BoundsCheck, ...

  2. 分享.net常见的内存泄露及解决方法

    分享.net常见的内存泄露及解决方法 关于内存泄漏的问题,之前也为大家介绍过,比如:<C++中内存泄漏的检测方法介绍>,是关于C++内存泄漏的.今天为大家介绍的是关于.NET内存泄漏的问题 ...

  3. CPP-基础:内存泄露及其检测工具

    [转]浅谈C/C++内存泄露及其检测工具   对于一个c/c++程序员来说,内存泄漏是一个常见的也是令人头疼的问题.已经有许多技术被研究出来以应对这个问题,比如 Smart Pointer,Garba ...

  4. [转]浅谈C/C++内存泄露及其检测工具

    转自:http://www.cnblogs.com/taoxu0903/archive/2007/10/27/939261.html 对于一个c/c++程序员来说,内存泄漏是一个常见的也是令人头疼的问 ...

  5. C/C++内存泄露及检测工具

    内存泄漏的定义   一般我们常说的内存泄漏是指堆内存的泄漏.堆内存是指程序从堆中分配的,大小任意的(内存块的大小可以在程序运行期决定),使用完后必须显示释放的内 存.应用程序一般使用malloc,re ...

  6. VC++ 内存泄露与检测的一种方法

        本文介绍,当VC++或者MFC程序,出现内存泄露时,如何快速定位的方法,这种方法有一定的局限性,在注意事项中会给出的. MFC程序     当MFC程序出现内存泄露时,退出程序时的VS调试输出 ...

  7. Windows系统中内存泄露与检测工具及方法

    1.检测需要使用的工具:windbg工具.检测前,需要先安装windbg工具.安装了该工具后,会在安装目录下有一个umdh工具.假设windbg安装在以下目录下:D:\Program Files\De ...

  8. C++中内存泄露的检测

    C++没有java的内存垃圾回收机制,在程序短的时候可能比较容易发现问题,在程序长的时候是否有什么检测的方法呢? 假设有一个函数可以某点检测程序的内存使用情况,那是否可以在程序开始的时候设置一个点,在 ...

  9. Android内存泄露自动检测神器LeakCanary

    经典的面试题: a.怎样在coding过程中避免内存泄露? b.怎样检测内存泄露? 这两个问题我想大部分Android 职位面试时都会被问到吧. 怎样避免就不赘述了,网上很多答案. 工具呢,当然也有很 ...

随机推荐

  1. asterisk-java ami2 事件监听

    asteriskServer文章1提到啦怎么获取,就不解释 asteriskServer.addChainListener(new AsteriskeventListenerInit());//整个服 ...

  2. JAVA-Web04

    1 理解dom解析器机制   1)dom解析和dom4j原理一致   2)Node是所有元素的父接口   3)常用的API: DocumentBuilderFactory factory = Docu ...

  3. 【Python图像特征的音乐序列生成】一个更科学的图片分类参考方法,以及一个看起来很好用的数据集

    数据集地址:http://www.imageemotion.org/ 论文地址:http://www.doc88.com/p-1905670442096.html

  4. 查看nvidia的GPU

    nvidia-smi就可以查看,可以看到进程的占用率,可以kill杀掉进程 注意这里的-前后都不要空格,连起来写

  5. Python列表解析与生成器表达式

    Python列表解析 l = ["egg%s" %i for i in range(100) if i > 50] print(l) l= [1,2,3,4] s = 'he ...

  6. JavaScript -- 内置对象数组

    数组 创建数组的基本方式有两种: 1.使用 Array构造函数 语法:new Array() 小括号( )说明: (1)预先知道数组要保存的项目数量 (2)向Array构造函数中传递数组应包含的项 2 ...

  7. jquery源码学习第一天

    第一天认识了jquery的大体结构,总的大范围是 (function() { // 这里是封装的代码,包括了各种方法.工具 window.JQuery = JQuery window.$ = $; } ...

  8. MySQL左右连接查询中的NULL的数据筛选问题

    这里使用左连接为例子,对于左连接是将左边表的数据显示,右边表中如果没有对应的数据则使用null填充. game表: game_type表: SELECT g.name,g.type_id,t.type ...

  9. Docker自学纪实(一)Docker介绍

    先简单了解一下,做个记录,以便不时之需. Docker简介:Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从Apache2.0协议开源. Docker 可以让开发者打包他们的应用以及依 ...

  10. Unity基础-编辑器

    编辑器 Special Folders Hidden Folder(start with .) Standard Assets:第一批加载的文件 Editor:只在编辑下才能使用, Plugins R ...