用Linux内存泄露工具valgrind进行内存检查

29 篇文章 0 订阅
25 篇文章 0 订阅

用Linux内存泄露工具valgrind进行内存检查

valgrind介绍

 Memcheck:这是valgrind应用最广泛的工具,一个重量级的内存检查器,能够发现开发中绝大多数内存错误使用情况,比如:使用未初始化的内存,使用已经释放了的内存,内存访问越界等。这也是本文将重点介绍的部分。

命令:valgrind --tool=memcheck --leak-check=full --show-reachable=yes ./test

其中--leak-check=full指的是完全检查内存泄露,--show-reachable=yes是显示内存泄露的地点,--trace-children=yes是跟踪子进程。

测试程序:

 


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
    printf("\n begin... \n");

    int nNum = 0;
    while(1)
    {
        usleep(100000);
        char *p = (char *)malloc(1024);
        char *pp = (char *)malloc(2048);
        printf("\n p = %p, pp = %p \n", p, pp);
        free(p);
        char *ppp = (char *)malloc(1280);
        printf("\n ppp = %p \n", ppp);
        nNum++;
        if(nNum == 100)
        {
            break;
        }
    }
    printf("\n end... \n");
    return 1;
}

执行 valgrind --tool=memcheck --leak-check=full --show-reachable=yes ./test命令后

从上图中可以看出:

a) 堆总结(heap summary):

    程序退出时还在使用的内存为332800bytes,分为200个块(即200次malloc);

    总共的堆申请次数是300次,释放次数是100次,共申请内存435200bytes

b)  接下来是内存泄露点

    1)         main.cpp:17行分配内存100次,分配内存大小为128000bytes,确认丢失内存为128000bytes

    2)         main.cpp:14行分配内存100次,确认丢失内存204800bytes.

c)  内存泄露总结:

    泄露332800bytes,在200个块中。

使用json库造成的内存泄露

执行valgrind --tool=memcheck --leak-check=full --show-reachable=yes ./test命令后

前三个红框表示内存错误的地址,最后一个方框表示错误个数;

第一红框中的错误指出在test文件中的struct_to_json_n中出现问题,其问题在于调用memory.c中44行,jsonp_strdup函数是该错误所在的函数,还有memory.c的23行.其所在函数是jsonp_malloc。对源码所在函数进行解读,发现在使用json_dumps函数时调用了memory.c中的以上两个函数,即申请了内存空间没有释放,故出内存泄露。

第二个红框表示main函数中有申请内存没有释放的情况,查看main函数发现对数组的内存没有释放

第三个红框中的错误指出在test文件中的struct_to_json_n中出现问题,其问题在于调用value.c中的json_array时出现问题,与第一个红框中的排查方法一致。

解决使用json库后的内存泄露

根据上图提示的错误,查看源码可知,均是由于内存没有释放所造成的内存泄露,对源test.c进行修改:

 


#include <stdio.h>
#include <string.h>

#include "jansson.h"
#include "upu_struct.h"
#include "upu_proto_parse.h"

// pMtInfo -> 传入 mtinfo 结构的首地址
// nNum    -> 传入 mtinfo 结构的数量
// pLen    -> C 结构转换成 JSON 结构字符串后的长度

// 实现功能:
// 将传入结构体 pMtInfo 中包含的数据内容转换成 JSON 字符串返回
char* struct_to_json_n( mtinfo *pMtInfo, int nNum, int *pLen )
{
    json_t *object=NULL;
	json_t *array=NULL;
	int i,size;
	char *result=NULL;
	char *CurResult=NULL;
	
	array=json_array();

	
	for(i=0;i<nNum;++i)
	{
	object=json_object();
	
	//结构体 pMtInfo 中包含的数据内容
	const char* pMoid=mt_get_moid(&pMtInfo[i]);
	const char* pE164=mt_get_e164(&pMtInfo[i]);
	const char* pPrototype=mt_get_prototype(&pMtInfo[i]);
	const char* pMttype=mt_get_mttype(&pMtInfo[i]);
	const char* pMtstate=mt_get_mtstate(&pMtInfo[i]);
	const char* pMtip=mt_get_mtip(&pMtInfo[i]);
	const char* pNuip=mt_get_nuip(&pMtInfo[i]);
	const char* pUserdomain=mt_get_userdomain(&pMtInfo[i]);
	const char* pDevid=mt_get_devid(&pMtInfo[i]);
	
	//将结构体 pMtInfo 中包含的数据内容转换为json格式
	
	json_t *pJsonMoid=json_string(pMoid);
	json_t *pJsonE164=json_string(pE164);
	json_t *pJsonPrototype=json_string(pPrototype);
	json_t *pJsonMttype=json_string(pMttype);
	json_t *pJsonMtstate=json_string(pMtstate);
	json_t *pJsonMtip=json_string(pMtip);
	json_t *pJsonNuip=json_string(pNuip);
	json_t *pJsonUserdomain=json_string(pUserdomain);
	json_t *pJsonDevid=json_string(pDevid);
	
	//将json结构的内容整合为object
	json_object_set_new(object, "Moid", pJsonMoid);
	json_object_set_new(object, "E164", pJsonE164);
	json_object_set_new(object, "Prototype", pJsonPrototype);
	json_object_set_new(object, "Mttype", pJsonMttype);
	json_object_set_new(object, "Mtstate", pJsonMtstate);
	json_object_set_new(object, "Mtip", pJsonMtip);
	json_object_set_new(object, "Nuip", pJsonNuip);
	json_object_set_new(object, "Userdomain", pJsonUserdomain);
	json_object_set_new(object, "Devid", pJsonDevid);
		
	int size1=json_object_size(object);
	printf("[%d]:size1=%d\n",i,size1);
	//将本结构体数组转化为json格式的字符串
	CurResult=json_dumps(object, JSON_PRESERVE_ORDER);
	printf("CurResult=%s\n",CurResult);

jsonp_free(CurResult);

//将本字符串添加到json结构体数组中 json_array_insert_new(array,i,object); //json_decref(object); } size=json_array_size(array); printf("size=%d\n",size); result=json_dumps(array,JSON_PRESERVE_ORDER); //jsonp_free(result);

json_decref(array);

return result; } int main() { int i = 0; int nLen = 0; int nNum = 5; char *pJsonToString=NULL; mtinfo *pMtInfoArray = NULL; pMtInfoArray = (mtinfo *)malloc( nNum * sizeof(mtinfo) ); memset( pMtInfoArray, 0, nNum * sizeof(mtinfo) ); // 通过函数 mt_set_e164 设置 E164 号 0512111885621 ~ 0512111885625 到结构 pMtInfoArray[n] 中 mt_set_e164(&pMtInfoArray[0],"0512111885621"); mt_set_e164(&pMtInfoArray[1],"0512111885622"); mt_set_e164(&pMtInfoArray[2],"0512111885623"); mt_set_e164(&pMtInfoArray[3],"0512111885624");        mt_set_e164(&pMtInfoArray[4],"0512111885625"); pJsonToString=struct_to_json_n( pMtInfoArray, nNum, &nLen ); printf("pJsonTosTring=%s\n",pJsonToString);

jsonp_free(pJsonToString);

free(pMtInfoArray);

return 0; }

其中加粗部分为修改加入的内容,再对其进行内存泄露检测:

由图可知,内存泄露已经解决。

原文地址:https://my.oschina.net/BambooLi/blog/514961

 

2. 对于结构复杂的程序,如涉及模板类及复杂的调用,gdb得出了出错位置,似乎这还不够,这时候要使用更为专业的工具——valgrind。

valgrind是一款专门用作内存调试,内存泄露检测的开源工具软件,valgrind这个名字取自北欧神话英灵殿的入口,不过,不能不承认,它确实是Linux下做内存调用分析的神器。一般Linux系统上应该没有自带valgrind,需要自行进行下载安装。

下载地址:http://valgrind.org/downloads/current.html

进入下载文件夹,分别执行(需要root权限,且必须按默认路径安装,否则有加载错误):

./configure

make

make install

安装成功后,使用类似如下命令启动程序:

valgrind --tool=memcheck --leak-check=full --track-origins=yes --leak-resolution=high --show-reachable=yes --log-file=memchecklog ./controller_test

其中,–log-file=memchecklog指记录日志文件,名字为memchecklog;–tool=memcheck和–leak-check=full用于内存检测。

可以得到类似的记录:

==23735==
==23735== Thread 1:
==23735== Invalid read of size 4
==23735== at 0x804F327: ResourceHandler<HBMessage>::~ResourceHandler() (ResourceHandler.cpp:48)
==23735== by 0x804FDBE: ConnectionManager<HBMessage>::~ConnectionManager() (ConnectionManager.cpp:74)
==23735== by 0×8057288: MainThread::~MainThread() (MainThread.cpp:73)
==23735== by 0x8077B2F: main (Main.cpp:177)
==23735== Address 0×0 is not stack’d, malloc’d or (recently) free’d
==23735==

可以看到说明为无法访问Address 0x0,明显为一处错误。

这样valgrind直接给出了出错原因以及程序中所有的内存调用、释放记录,非常智能,在得知错误原因的情况下,找出错误就效率高多了。

再说一句,valgrind同时给出了程序的Memory Leak情况的报告,给出了new-delete对应情况,所有泄漏点位置给出,这一点在其他工具很难做到,十分好用。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值