此文内容摘自

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. SharePoint 2016 如何修改Library 地址

    Scenario #1 如何为一个Library 修改下访问 网络路径地址 1.点击library,点开open with explorer,使用Windows资源管理器打开文档库 2.在文件夹层次结 ...

  2. java面试题(杨晓峰)---第五讲String、StringBuffer、StringBuilder有什么区别?

    线程 字符 操作频繁度 1 String (1)String的创建机制 由于String在java世界中使用过于频繁,java为了避免在一个系统中产生大量重复的String对象,引入了字符串常量池,其 ...

  3. NGUI类之间的关系架构

    NGUI Drawcall 1.使用同一个altals的元素尽量放在同一个UIPanel下面,在NGUI中,它消耗的drawcall是以每个Panel为独立计算单位进行计算的. 2.如果一个UIPan ...

  4. Ajax经典的面试题

    1.什么是AJAX,为什么要使用Ajax(请谈一下你对Ajax的认识)什么是ajax:AJAX是“Asynchronous JavaScript and XML”的缩写.他是指一种创建交互式网页应用的 ...

  5. MySQL Innodb表空间不足的处理方法

    官方给出的解决方案: 添加和删除 InnoDB 数据和日志文件 这一节描述在InnoDB表空间耗尽空间之时,或者你想要改变日志文件大小之时,你可以做的一些事情. 最简单的,增加InnoDB表空间大小的 ...

  6. Nginx正向代理代理http和https服务

    Nginx正向代理代理http和https服务 1. 背景需求 通过Nginx正向代理,去访问外网.可实现局域网不能访问外网的能力,以及防止在上网行为上,留下访问痕迹. 2. 安装配置 2.1安装 w ...

  7. Check for Palindromes-freecodecamp算法题目

    Check for Palindromes(检查回文字符串) 要求 给定的字符串是回文,返回true,反之,返回false.(如果一个字符串忽略标点符号.大小写和空格,正着读和反着读一模一样,那么这个 ...

  8. Choose unique values for the 'webAppRootKey' context-param in your web.xml files! 错误的解决

    大意是Log4jConfigListener在获取webapp.root值时,被后一context的值替换掉了,所以要在各个项目的web.xml中配置不同的webAppRootKey值,随即在其中一个 ...

  9. 【jquery】 form ajaxSubmit 问题

    常见问题 这个插件跟哪些版本的jQuery兼容? 这个插件需要jQuery v1.0.3 或 以后的版本. 这个插件需要其它插件的支持吗? 不需要. 这个插件的运行效率高吗? 是的!请到 对比页面 查 ...

  10. Goroutine 中执行匿名函数 坑

    //相对应for 循环 goroutine跑到慢 所以这里很大概率只会打印最后一条数据 func goRun() { values := []int{1, 2, 3} for _, v := rang ...