分类:C/C++/C#

Linux C/C++ 内存泄漏检测工具:Valgrind

Valgrind 是一款 Linux下(支持 x86、x86_64和ppc32)程序的内存调试工具,它可以对编译后的二进制程序进行内存使用监测(C语言中的malloc和free,以及C++中的new和delete),找出内存泄漏问题。

Valgrind 中包含的 Memcheck 工具可以检查以下的程序错误:

使用未初始化的内存 (Use of uninitialised memory)
使用已经释放了的内存 (Reading/writing memory after it has been free’d)
使用超过malloc分配的内存空间(Reading/writing off the end of malloc’d blocks)
对堆栈的非法访问 (Reading/writing inappropriate areas on the stack)
申请的空间是否有释放 (Memory leaks – where pointers to malloc’d blocks are lost forever)
malloc/free/new/delete申请和释放内存的匹配(Mismatched use of malloc/new/new [] vs free/delete/delete [])
src和dst的重叠(Overlapping src and dst pointers in memcpy() and related functions)
重复free

1、编译安装 Valgrind:


wget http://valgrind.org/downloads/valgrind-3.4.1.tar.bz2
tar xvf valgrind-3.4.1.tar.bz2
cd valgrind-3.4.1/
./configure --prefix=/usr/local/webserver/valgrind
make
make install

2、使用示例:对“ls”程序进程检查,返回结果中的“definitely lost: 0 bytes in 0 blocks.”表示没有内存泄漏。


[root@xoyo42 /]#/usr/local/webserver/valgrind/bin/valgrind --tool=memcheck --leak-check=full ls /
==1157== Memcheck, a memory error detector.
==1157== Copyright (C) 2002-2008, and GNU GPL'd, by Julian Seward et al.
==1157== Using LibVEX rev 1884, a library for dynamic binary translation.
==1157== Copyright (C) 2004-2008, and GNU GPL'd, by OpenWorks LLP.
==1157== Using valgrind-3.4.1, a dynamic binary instrumentation framework.
==1157== Copyright (C) 2000-2008, and GNU GPL'd, by Julian Seward et al.
==1157== For more details, rerun with: -v
==1157==
bin   data0  dev  home  lib64       media  mnt  opt   root  selinux  sys       tcsql.db.idx.pkey.dec  ttserver.pid  var
boot  data1  etc  lib   lost+found  misc   net  proc  sbin  srv      tcsql.db  tmp                    usr
==1157==
==1157== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 5 from 1)
==1157== malloc/free: in use at exit: 28,471 bytes in 36 blocks.
==1157== malloc/free: 166 allocs, 130 frees, 51,377 bytes allocated.
==1157== For counts of detected errors, rerun with: -v
==1157== searching for pointers to 36 not-freed blocks.
==1157== checked 174,640 bytes.
==1157==
==1157== LEAK SUMMARY:
==1157==    definitely lost: 0 bytes in 0 blocks.
==1157==      possibly lost: 0 bytes in 0 blocks.
==1157==    still reachable: 28,471 bytes in 36 blocks.
==1157==         suppressed: 0 bytes in 0 blocks.
==1157== Reachable blocks (those to which a pointer was found) are not shown.
==1157== To see them, rerun with: --leak-check=full --show-reachable=yes

3、使用示例:对一个使用libevent库编写的“httptest”程序进程检查,返回结果中的“definitely lost: 255 bytes in 5 blocks.”表示发生内存泄漏。


[root@xoyo42 tcsql-0.1]# /usr/local/webserver/valgrind/bin/valgrind --tool=memcheck --leak-check=full ./httptest
==1274== Memcheck, a memory error detector.
==1274== Copyright (C) 2002-2008, and GNU GPL'd, by Julian Seward et al.
==1274== Using LibVEX rev 1884, a library for dynamic binary translation.
==1274== Copyright (C) 2004-2008, and GNU GPL'd, by OpenWorks LLP.
==1274== Using valgrind-3.4.1, a dynamic binary instrumentation framework.
==1274== Copyright (C) 2000-2008, and GNU GPL'd, by Julian Seward et al.
==1274== For more details, rerun with: -v
==1274==
==1274== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1005 from 2)
==1274== malloc/free: in use at exit: 402,291 bytes in 74 blocks.
==1274== malloc/free: 15,939 allocs, 15,865 frees, 6,281,523 bytes allocated.
==1274== For counts of detected errors, rerun with: -v
==1274== searching for pointers to 74 not-freed blocks.
==1274== checked 682,468,160 bytes.
==1274==
==1274== 255 bytes in 5 blocks are definitely lost in loss record 17 of 32
==1274==    at 0x4A05FBB: malloc (vg_replace_malloc.c:207)
==1274==    by 0x3C1D809BC6: evhttp_decode_uri (http.c:2105)
==1274==    by 0x401C75: tcsql_handler (in /data0/tcsql/cankao/tcsql-0.1/tcsql)
==1274==    by 0x3C1D80C88F: evhttp_get_body (http.c:1582)
==1274==    by 0x3C1D8065F7: event_base_loop (event.c:392)
==1274==    by 0x403E2F: main (in /data0/tcsql/cankao/tcsql-0.1/tcsql)
==1274==
==1274== LEAK SUMMARY:
==1274==    definitely lost: 255 bytes in 5 blocks.
==1274==      possibly lost: 0 bytes in 0 blocks.
==1274==    still reachable: 402,036 bytes in 69 blocks.
==1274==         suppressed: 0 bytes in 0 blocks.
==1274== Reachable blocks (those to which a pointer was found) are not shown.
==1274== To see them, rerun with: --leak-check=full --show-reachable=yes

检查httptest程序,发现有一处“char *decode_uri = evhttp_decode_uri(evhttp_request_uri(req));”中的“decode_uri”没有被free,再程序处理完成后加上“free(decode_uri);”后,再使用Valgrind检查,结果已经是“definitely lost: 0 bytes in 0 blocks.”。

转自:http://www.s135.com/post/419/


jni内存泄露

在c++中new的对象,如果不返回java,必须用release掉,否则内存泄露。包括NewStringUTF,NewObject
。如果返回java不必release,java会自己回收。

jstring jstr = env->NewStringUTF((*p).sess_id);

env->DeleteLocalRef( jstr);

jobject jobj = env->NewObject(clazz,midInit);
return jobj;

内存泄露可以先从windows资源管理器中,看到随程序运行,内存不断增长的趋势,具体可以用hp jmeter检测在运行程序时,加jvm参数 -Xrunhprof:heap=all,cutoff=0 ,生成java.hprof.txt,用jmeter打开,Metric -> Residual Objects (Count),可以看到未回收的对象,选中要查看的对象,点Mark记录下要查看的对象,Window -> New Window 打开新窗口,用Metric -> Reference Graph Tree,然后点Find Immediately可以看到对象被哪里引用。

找出内存泄漏另一方法

程序有内存泄漏的第一个迹象通常是它抛出一个 DE>OutOfMemoryErrorDE>,或者因为频繁的垃圾收集而表现出糟糕的性能。幸运的是,垃圾收集可以提供能够用来诊断内存泄漏的大量信息。如果以 DE>-verbose:gcDE> 或者 DE>-XloggcDE> 选项调用 JVM,那么每次 GC 运行时在控制台上或者日志文件中会打印出一个诊断信息,包括它所花费的时间、当前堆使用情况以及恢复了多少内存。记录 GC 使用情况并不具有干扰性,因此如果需要分析内存问题或者调优垃圾收集器,在生产环境中默认启用 GC 日志是值得的。

有工具可以利用 GC 日志输出并以图形方式将它显示出来,JTune 就是这样的一种工具(请参阅 参考资料)。观察 GC 之后堆大小的图,可以看到程序内存使用的趋势。对于大多数程序来说,可以将内存使用分为两部分:baseline 使用和current load 使用。对于服务器应用程序,baseline 使用就是应用程序在没有任何负荷、但是已经准备好接受请求时的内存使用,current load 使用是在处理请求过程中使用的、但是在请求处理完成后会释放的内存。只要负荷大体上是恒定的,应用程序通常会很快达到一个稳定的内存使用水平。如果在应用程序已经完成了其初始化并且负荷没有增加的情况下,内存使用持续增加,那么程序就可能在处理前面的请求时保留了生成的对象。

 

图 1 显示  GC 之后应用程序堆大小随着时间的变化图。上升趋势是存在内存泄漏的警示信号。(在真实的应用程序中,坡度不会这么大,但是在收集了足够长时间的 GC 数据后,上升趋势通常会表现得很明显。)
图 1. 持续上升的内存使用趋势

确信有了内存泄漏后,下一步就是找出哪种对象造成了这个问题。所有内存分析器都可以生成按照对象类进行分解的堆快照。有一些很好的商业堆分析工具,但是找出内存泄漏不一定要花钱买这些工具 —— 内置的 DE>hprofDE> 工具也可完成这项工作。要使用 DE>hprofDE> 并让它跟踪内存使用,需要以 DE>-Xrunhprof:heap=sitesDE> 选项调用 JVM。

清单 3 显示分解了应用程序内存使用的 DE>hprofDE> 输出的相关部分。(DE>hprofDE> 工具在应用程序退出时,或者用 DE>kill -3DE> 或在 Windows 中按 Ctrl+Break 时生成使用分解。)注意两次快照相比,DE>Map.EntryDE>、DE>TaskDE> 和 DE>int[]DE> 对象有了显著增加。

请参阅 清单 3

清单 4 展示了 DE>hprofDE> 输出的另一部分,给出了 DE>Map.EntryDE> 对象的分配点的调用堆栈信息。这个输出告诉我们哪些调用链生成了 DE>Map.EntryDE> 对象,并带有一些程序分析,找出内存泄漏来源一般来说是相当容易的。
清单 4. HPROF 输出,显示 Map.Entry 对象的分配点

DE>    TRACE 300446:   java.util.HashMap$Entry.<init>(<Unknown Source>:Unknown line)   java.util.HashMap.addEntry(<Unknown Source>:Unknown line)   java.util.HashMap.put(<Unknown Source>:Unknown line)   java.util.Collections$SynchronizedMap.put(<Unknown Source>:Unknown line)   com.quiotix.dummy.MapLeaker.newTask(MapLeaker.java:48)   com.quiotix.dummy.MapLeaker.main(MapLeaker.java:64)  DE>

另外
jstring jstr = (jstring)env->CallObjectMethod(authenRequest, mid_authenReq_getSdId_S);
env->GetStringUTFRegion(jstr,0,env->GetStringLength(jstr),authenReq.sd_id);
当jstr是null时,env->GetStringLength(jstr)会出错,导致jvm崩溃

FROM: http://www.blogjava.net/neumqp/archive/2006/03/02/33152.html


去年写的文本批量查找器改进版

下载地址:文本批量查找器Archive


新开发的FlashPaper转换服务器

工作方式:

网站接收用户上传的doc exl pdf txt 等源文档,存放在一个需要http auth认证的目录下,防止网站用户web方式读取

然后把要转换的文档存mysql中,供fpserver转换

fpserver采用线下转换方式,比如当一台fpserver转换速度较慢时,可以在另一台pc或是服务器上再运行一套程序,只需要设定不同的标识号即可!

不知道这算不算是分布式计算,嘿嘿,每台计算机上运行一套服务器程序,从web服务器获取要转换的文档并下载下来,转换,转换成功后上传。完善的机制保证下载失败或是转换失败再者上传失败等异常问题出现后的问题解决!

fpserver无需放置机房,通过http上传,只需网速ok就行!


目前正在开发一个c#的flashpaper在线转换服务器

转换服务器用.net开发,win7平台

网站采用apache 的 .htpasswd http认证 采用密码保护用户上传的doc等文档源文件。

fp服务器自动从web中依次取得用户上传的doc文档,并且转换后回调web上传接口,实现文档的在线转换

下面的代码是下载web上的源文档用于在线转换

[codesyntax lang=”csharp”]

 try
            {
                String url = "http://localhost:82/api/T1yAdWXgdGXXb1upjX.jpg";
                String fileName = url.Substring(url.LastIndexOf("/") + 1);
                String refer = url.Substring(0, url.LastIndexOf("/") + 1);

                System.Net.HttpWebRequest req = System.Net.HttpWebRequest.Create(url) as System.Net.HttpWebRequest;
                req.AllowAutoRedirect = true;
                req.Referer = refer;
                /*发送http认证*/
                req.Credentials = new NetworkCredential("xzy", "xzy");  
                req.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13";
                System.Net.HttpWebResponse res = req.GetResponse() as System.Net.HttpWebResponse;
                System.IO.Stream stream = res.GetResponseStream();
                byte[] buffer = new byte[32 * 1024];
                int bytesProcessed = 0;
                System.IO.FileStream fs = System.IO.File.Create("tmp/down/" + fileName);
                int bytesRead;
                do
                {
                    bytesRead = stream.Read(buffer, 0, buffer.Length);
                    fs.Write(buffer, 0, bytesRead);
                    bytesProcessed += bytesRead;
                }
                while (bytesRead > 0);
                fs.Flush();
                fs.Close();
                res.Close();
            }
            catch(Exception err)
            {
                MessageBox.Show(err.Message);
            }

[/codesyntax]


qq机器人xqqrobot加上了主动发送信息功能

主动发送信息实现过程:

机器人通过http去指定的url上去获取单条要给机器人发送的信息,为空的话,隔5秒后再取,不为空,取出并且机器人发送本条信息,同时下次取信息时,会把这条已发送的信息的ID通过POST传给http,通知web程序本条信息已成功发出!

程序写好,编译也通过了,但是公司上网要走公司的代理,所以qq机器人暂时还没有通过测试,先在博客里记录一下,回家后再测

目前机器人处开发阶段,设定了一个时间,机器人登陆后60秒左右后会自动下线!

xqqrobot_1224


搞定了qq机器人linux编译后内存泄漏问题

目前linux版本已正常工作,上周windows版本也存在内存泄漏问题,找了半天才发现是因为数组过界引的

另今天移值到linux平台,都是用gcc windows下正常 linux下就内存泄漏,怪事。。不过还好找到了问题所在。

另新加了一个程序自动从文本文件里读取验证码的功能,方便linux在nohup下运行,无需担心验证码输入的问题。

目前程序挂服务器上进行测试,如不稳定继续修改!

linux.jpg


花了些时间弄个QQ机器人

qq通信服务端是在myqq上二次开发,所以支持linux/windows双平台

主控程序采用php开发

主要的功能是:

查ip地址、查电话归属地、查天气预报、查pr值、在线翻译等都是些常用的功能

目前windows下正常,准备着手迁移至linux平台,还好机器人程序的主要库libcurl是跨平台的。

qq.jpg


新写的一个.net小程序,用于批量搜索源码内容

主要是解决在工作中,有些需要在大批量的源文件或是html中搜索文本中包括一些关键词的操作。比如搜索全部的html,查找出哪个文章被挂了马,又比如说查看一个开源软件源码时,要找到一个函数定义所在文件。有了这个小软件,就方便多了

目前是第一版只支持utf-8编码,过段时间,加上编码转换功能,就可以支持其它编码了!编码只在搜索中文时有影响,英文不受影响

程序截图

txtsearch.png

程序下载

txtsearch.zip


用c++把自动新建、修改虚拟主机的shell重写了一下

 

以后想自己写个ubuntu下的虚拟主机管理系统,嘿嘿!目前已搞定了apache新建用户、删除用户、vsftp mysql管理。

C++代码
  1. #include <iostream>   
  2. #include <fstream>   
  3. #include <string>   
  4. #include<stdlib.h>   
  5.   
  6. using namespace std;   
  7. string stringReplace(const string& input,const string& find,const string& replaceWith)   
  8.   
  9. {   
  10.     string   strOut(input);   
  11.     int   curPos   =   0;   
  12.     int   pos;   
  13.     while((pos   =   strOut.find(find,   curPos))   !=   -1)   
  14.     {   
  15.         strOut.replace(pos,   find.size(),   replaceWith);   
  16.         curPos   =   pos   +   replaceWith.size();   
  17.     }   
  18.     return   strOut;   
  19. }   
  20.   
  21.   
  22.   
  23. int main(int argc,char *argv[])   
  24. {   
  25.         int i=3;   
  26.         cout<<argv[1]<<"|"<<argv[2]<<endl;   
  27.         if(argv[1]=="diyweb"){   
  28.                 cout<<"error,diyweb is system user"<<endl;   
  29.                 return 0;   
  30.         }   
  31.         if(argv[1]=="000-default"){   
  32.                 cout<<"error,000-default is system user"<<endl;   
  33.                 return 0;   
  34.         }   
  35.         //cin.get();   
  36.         string filename="/etc/apache2/sites-enabled/"+string(argv[1]);   
  37.   
  38.         ofstream f1(filename.c_str());   
  39.   
  40.         if(!f1){   
  41.                 cout<<"error,file not open!"<<endl;   
  42.                 return 0;   
  43.         }   
  44.         string doname=stringReplace(string(argv[2]),"@"," ");   
  45.         string content="<VirtualHost *:80>\nServerName "+string(argv[1])+".ye55.net \nServerAlias "+string(argv[1])+".armos.cn "+doname+" \nDocumentRoot \"/home/web/diyweb/company/"+string(argv[1])+"\"\n</VirtualHost>";   
  46.         f1<<content<<endl;   
  47.         f1.close();   
  48.         system("sudo /etc/init.d/apache2 reload >tmp.out");   
  49.         cout<<"success"<<endl;   
  50.         return 0;   
  51.   
  52. }