【3】Hadoop中常出现的错误以及解决方法 - 数据库 - Tech - ITeye论坛
1:Shuffle Error: Exceeded MAX_FAILED_UNIQUE_FETCHES; bailing-out
Answer:
程序里面需要打开多个文件,进行分析,系统一般默认数量是1024,(用ulimit -a可以看到)对于正常使用是够了,但是对于程序来讲,就太少了。
修改办法:
修改2个文件。
/etc/security/limits.conf
vi /etc/security/limits.conf
加上:
* soft nofile 102400
* hard nofile 409600
$cd /etc/pam.d/
$sudo vi login
添加 session required /lib/security/pam_limits.so
2:Too many fetch-failures
Answer:
出现这个问题主要是结点间的连通不够全面。
1) 检查 、/etc/hosts
要求本机ip 对应 服务器名
要求要包含所有的服务器ip + 服务器名
2) 检查 .ssh/authorized_keys
要求包含所有服务器(包括其自身)的public key
3:处理速度特别的慢 出现map很快 但是reduce很慢 而且反复出现 reduce=0%
Answer:
结合第二点,然后
修改 conf/hadoop-env.sh 中的export HADOOP_HEAPSIZE=4000
4:能够启动datanode,但无法访问,也无法结束的错误
在重新格式化一个新的分布式文件时,需要将你NameNode上所配置的dfs.name.dir这一namenode用来存放NameNode 持久存储名字空间及事务日志的本地文件系统路径删除,同时将各DataNode上的dfs.data.dir的路径 DataNode 存放块数据的本地文件系统路径的目录也删除。如本此配置就是在NameNode上删除/home/hadoop/NameData,在DataNode上删除/home/hadoop/DataNode1和/home/hadoop/DataNode2。这是因为Hadoop在格式化一个新的分布式文件系统时,每个存储的名字空间都对应了建立时间的那个版本(可以查看/home/hadoop /NameData/current目录下的VERSION文件,上面记录了版本信息),在重新格式化新的分布式系统文件时,最好先删除NameData 目录。必须删除各DataNode的dfs.data.dir。这样才可以使namedode和datanode记录的信息版本对应。
注意:删除是个很危险的动作,不能确认的情况下不能删除!!做好删除的文件等通通备份!!
5:java.io.IOException: Could not obtain block: blk_194219614024901469_1100 file=/user/hive/warehouse/src_20090724_log/src_20090724_log
出现这种情况大多是结点断了,没有连接上。
6:java.lang.OutOfMemoryError: Java heap space
出现这种异常,明显是jvm内存不够得原因,要修改所有的datanode的jvm内存大小。
Java -Xms1024m -Xmx4096m
一般jvm的最大内存使用应该为总内存大小的一半,我们使用的8G内存,所以设置为4096m,这一值可能依旧不是最优的值。(其实对于最好设置为真实物理内存大小的0.8)
7:出现map%,但是呢reduce到98%左右的时候呢,就直接进failedjobs了
解决办法:
检查mapred.map.tasks是不是设置的太多了,设置太多的话会导致处理大量的小文件
检查mapred.reduce.parallel.copies是否设置合适。
8:
系统根目录下的/tmp文件夹是不可以删除的
否则bin/hadoop jps
会出现异常:
Exception in thread "main" java.lang.NullPointerException at sun.jvmstat.perfdata.monitor.protocol.local.LocalVmManager.activeVms(LocalVmManager.java:127)
at sun.jvmstat.perfdata.monitor.protocol.local.MonitoredHostProvider.activeVms(MonitoredHostProvider.java:133)
at sun.tools.jps.Jps.main(Jps.java:45)
同时
bin/hive
Unable to create log directory /tmp/hadoopuser
2:Too many fetch-failures
Answer:
出现这个问题主要是结点间的连通不够全面。
1) 检查 、/etc/hosts
要求本机ip 对应 服务器名
要求要包含所有的服务器ip + 服务器名
2) 检查 .ssh/authorized_keys
要求包含所有服务器(包括其自身)的public key
3:处理速度特别的慢 出现map很快 但是reduce很慢 而且反复出现 reduce=0%
Answer:
结合第二点,然后
修改 conf/hadoop-env.sh 中的export HADOOP_HEAPSIZE=4000
4:能够启动datanode,但无法访问,也无法结束的错误
在重新格式化一个新的分布式文件时,需要将你NameNode上所配置的dfs.name.dir这一namenode用来存放NameNode 持久存储名字空间及事务日志的本地文件系统路径删除,同时将各DataNode上的dfs.data.dir的路径 DataNode 存放块数据的本地文件系统路径的目录也删除。如本此配置就是在NameNode上删除/home/hadoop/NameData,在DataNode上删除/home/hadoop/DataNode1和/home/hadoop/DataNode2。这是因为Hadoop在格式化一个新的分布式文件系统时,每个存储的名字空间都对应了建立时间的那个版本(可以查看/home/hadoop /NameData/current目录下的VERSION文件,上面记录了版本信息),在重新格式化新的分布式系统文件时,最好先删除NameData 目录。必须删除各DataNode的dfs.data.dir。这样才可以使namedode和datanode记录的信息版本对应。
注意:删除是个很危险的动作,不能确认的情况下不能删除!!做好删除的文件等通通备份!!
5:java.io.IOException: Could not obtain block: blk_194219614024901469_1100 file=/user/hive/warehouse/src_20090724_log/src_20090724_log
出现这种情况大多是结点断了,没有连接上。
6:java.lang.OutOfMemoryError: Java heap space
出现这种异常,明显是jvm内存不够得原因,要修改所有的datanode的jvm内存大小。
Java -Xms1024m -Xmx4096m
一般jvm的最大内存使用应该为总内存大小的一半,我们使用的8G内存,所以设置为4096m,这一值可能依旧不是最优的值。(其实对于最好设置为真实物理内存大小的0.8)
7:出现map%,但是呢reduce到98%左右的时候呢,就直接进failedjobs了
解决办法:
检查mapred.map.tasks是不是设置的太多了,设置太多的话会导致处理大量的小文件
检查mapred.reduce.parallel.copies是否设置合适。
8:
系统根目录下的/tmp文件夹是不可以删除的
否则bin/hadoop jps
会出现异常:
Exception in thread "main" java.lang.NullPointerException at sun.jvmstat.perfdata.monitor.protocol.local.LocalVmManager.activeVms(LocalVmManager.java:127)
at sun.jvmstat.perfdata.monitor.protocol.local.MonitoredHostProvider.activeVms(MonitoredHostProvider.java:133)
at sun.tools.jps.Jps.main(Jps.java:45)
同时
bin/hive
Unable to create log directory /tmp/hadoopuser
2:Too many fetch-failures
Answer:
出现这个问题主要是结点间的连通不够全面。
1) 检查 、/etc/hosts
要求本机ip 对应 服务器名
要求要包含所有的服务器ip + 服务器名
2) 检查 .ssh/authorized_keys
要求包含所有服务器(包括其自身)的public key
3:处理速度特别的慢 出现map很快 但是reduce很慢 而且反复出现 reduce=0%
Answer:
结合第二点,然后
修改 conf/hadoop-env.sh 中的export HADOOP_HEAPSIZE=4000
4:能够启动datanode,但无法访问,也无法结束的错误
在重新格式化一个新的分布式文件时,需要将你NameNode上所配置的dfs.name.dir这一namenode用来存放NameNode 持久存储名字空间及事务日志的本地文件系统路径删除,同时将各DataNode上的dfs.data.dir的路径 DataNode 存放块数据的本地文件系统路径的目录也删除。如本此配置就是在NameNode上删除/home/hadoop/NameData,在DataNode上删除/home/hadoop/DataNode1和/home/hadoop/DataNode2。这是因为Hadoop在格式化一个新的分布式文件系统时,每个存储的名字空间都对应了建立时间的那个版本(可以查看/home/hadoop /NameData/current目录下的VERSION文件,上面记录了版本信息),在重新格式化新的分布式系统文件时,最好先删除NameData 目录。必须删除各DataNode的dfs.data.dir。这样才可以使namedode和datanode记录的信息版本对应。
注意:删除是个很危险的动作,不能确认的情况下不能删除!!做好删除的文件等通通备份!!
5:java.io.IOException: Could not obtain block: blk_194219614024901469_1100 file=/user/hive/warehouse/src_20090724_log/src_20090724_log
出现这种情况大多是结点断了,没有连接上。
6:java.lang.OutOfMemoryError: Java heap space
出现这种异常,明显是jvm内存不够得原因,要修改所有的datanode的jvm内存大小。
Java -Xms1024m -Xmx4096m
一般jvm的最大内存使用应该为总内存大小的一半,我们使用的8G内存,所以设置为4096m,这一值可能依旧不是最优的值。(其实对于最好设置为真实物理内存大小的0.8)
7:出现map%,但是呢reduce到98%左右的时候呢,就直接进failedjobs了
解决办法:
检查mapred.map.tasks是不是设置的太多了,设置太多的话会导致处理大量的小文件
检查mapred.reduce.parallel.copies是否设置合适。
8:
系统根目录下的/tmp文件夹是不可以删除的
(jps is based on jvmstat and it needs to be able to secure a memory mapped file on the temporary file system.
)
否则bin/hadoop jps
会出现异常:
Exception in thread "main" java.lang.NullPointerException at sun.jvmstat.perfdata.monitor.protocol.local.LocalVmManager.activeVms(LocalVmManager.java:127)
at sun.jvmstat.perfdata.monitor.protocol.local.MonitoredHostProvider.activeVms(MonitoredHostProvider.java:133)
at sun.tools.jps.Jps.main(Jps.java:45)
同时
bin/hive
Unable to create log directory /tmp/hadoopuser
从HTML文件中抽取正文的简单方案 试验结果 - hzxdark - ITeye技术网站
一、 简介
本文是根据alexjc的<The Easy Way to Extract Useful Text from Arbitrary HTML>一文进行实验的结果。原文见:
http://ai-depot.com/articles/the-easy-way-to-extract-useful-text-from-arbitrary-html/
——alexjc原文
http://blog.csdn.net/lanphaday/archive/2007/08/13/1741185.aspx
——恋花蝶翻译的中英对照版本
该文章主要内容是讲述如何利用正文相对于其他文本,正文文本与生成该正文所需的html字节码的比值较大的规律,利用神经网络识别出正文过滤过滤广告的效果。主要设计如下:
1. 解析HTML代码并记下处理的字节数。
2. 以行或段的形式保存解析输出的文本。
3. 统计每一行文本相应的HTML代码的字节数
4. 通过计算文本相对于字节数的比率来获取文本密度
5. 最后用神经网络来决定这一行是不是正文的一部分。
二、 设计方案
本实验相对原本alexjc设计方案有几点修改:
1. 用RPROP(弹性BP网络)代替原文的感知器;
2. 由于原文并没有把文本长度、html字节长度做归一化,所以不采用原始文本长度、html字节长度作为特征值。相对的,对归一化后的文本长度、html字节长度,以及前向后向N行等各种组合进行试验。
3. 试验文本为任意在网上选取的10个网页,见附件。
4. 原文并没有提及,如何定义一行文本是否正文,所以这里定义了几个正文类型:
a) 内容型正文,特征是有长的连续文字段,定义这些文字段为正文;
b) 论坛型,有短的不连续的文字段,定义这些文字段为正文;
c) 论坛帖子列表型(部分试验将会对这类型进行训练查看效果,对于论坛帖子列表是否属于正文这里不做讨论……),帖子标题为正文;
d) 首页型,定义为没有正文(厄,谁能说出,新浪首页哪些是正文?)
实验环境:
1. 语言:JAVA,JRE1.5
2. 操作系统:windows xp
三、 实验过程:
1. 设计实现一个三层RPROP网络(令人惊讶的是,居然在这个领域没有人写一个开源的组件,apache等的开源巨头们都对neural network不感兴趣么?)。
/*
*初始化RPROP对象
*
*本函数用于创建训练前的RPROP对象
*参数:
* int in_num 输入层个数;
* int hidden_unit_num 隐含层节点个数
* int out_num 输出层个数
*
*/
public RPROP(int in_num, int hidden_unit_num, int out_num)
/*
*初始化RPROP对象
*
*本函数用于创建训练后的RPROP对象
*参数:
* int in_num 输入层个数;
* int hidden_unit_num 隐含层节点个数
* int out_num 输出层个数
* double[][] w1 隐含层权重
* double[][] w2 输出层权重
* double[] b1 隐含层偏离值
* double[] b2 输出层偏离值
*/
public RPROP(int in_num, int hidden_unit_num, int out_num, double[][] w1, double[][] w2, double[] b1, double[] b2)
/*
*计算输出结果
*
*参数:
* double[] p 输入参数
*返回值:
* double[] 输出结果
*/
public double[] output(double[] p)
/*
*训练
*
*参数:
* double[][] p
* 训练样本集
* double[][][] t
* 期望结果集, t[i][j][0] 期望结果, t[i][j][1]误差放大系数
* double goal
* 目标误差,注意,本网络用的是“方差”作为误差判断条件
* int epochs
* 训练最大次数
*/
public void train(double[][] p, double[][][] t, double goal,int epochs)
对于这个实现,有兴趣的朋友在本文最后下载附件。
2. 选取特征值
在实验中,笔者尝试了各种特征值组合:
1) 文本密度,文本长度,html字节码长度,前后各一行的同样数值;(原文设定)
2) 文本密度,文本长度倒数(归一化),前后各两行的同样数值;
3) 文本所在的html的链接密度(全文文本长度/总链接数,用于加强判断文本类型),文本密度,文本长度/5000(归一化,大于1的当1处理,下文简称为文本长度2),前后两行相同的数值;
4) 文本所在的html的链接密度,文本密度,文本长度2,前后两行相同的数值;
5) 文本所在的html的链接密度,文本密度,文本长度2,前后一行相同的数值;
6) 文本所在的html的链接密度,文本密度,文本长度2,前一行是否正文;
并规定,网络输出结果0为非正文,1为正文。
在训练过程中,发现训练过的网络命中率大部分落在0值部分,这是由于论坛这种短文段类型的网页会导致0值过多,训练时对0值过拟合。为了避免这一点,对某一篇网页的某一行的误差乘以该网页的0值与1值数量的比值。
3. 训练集获取
见附件。这是在笔者常浏览的网页中任意抽取的10个网页。对于期望输出的定义见上文。
四、实验结果
1. 1~5的实验,任意抽取部分样本集作为训练集,对于训练集拟合的很好,但对于测试集的表现却非常糟糕(请原谅笔者并没有记录实验数据);
这部分结果表明,以文本密度作为判断是否正文的特征值是有问题的。观察样本集的数据可以发现,即使是内容型的大段文字,也有可能文本密度很低——为了让网页变得更漂亮美观,现在有很多网站都对文字内容加了大段大段修饰用html代码……
鉴于这一点,笔者最终放弃文本密度作为特征值。而考虑到广告都是带链接的文本,相对的正文连接数则比较少,所以笔者认为,用文本长度/链接数 作为特征值或许会是一个更好的选择。
2. 6的实验,表现意外的非常的好(好到差点让笔者以为终于找到完美的解决方案……)
确实,即使是在测试集部分的表现也惊人好,但实际上有一个问题:每一行的计算受上一行计算的结果影响。测试集是事先定义每一行的上一行的结果,但在实际使用时,上一行的结果是实时计算出来的,所以就会出现,在某一行出错,导致后面的结果全部出错的情况……
至此,假如仍然坚持神经网络的解决方案,或许,采用:
文本长度,文本长度链接数,上一行的结果 做特征值, 采用三个弱分类器的ada-boost组合分类或许会是一个好的选择。
除此之外,实际上对正文的定义对结果也是有很大的影响。实际上,假如能根据数据化的东西定义某一个类别,那么对于该类别的划分,或许其实已经是可预知的,不如直接设计阈值处理。
笔者的实验则到此为止,并放弃了神经网络这个解决方案——直接采用这些特征值进行阈值判断,并对一些特殊部分设定过滤规则,这似乎比神经网络的表现来的简单、有效……
如果有哪位朋友感兴趣,并用ada-boost进行实验,笔者将非常期待这位朋友来交流下心得:)
附件:
neralNetwork.rar 源代码
res.rar 训练集
关于html文本抽取部分,这里用的是HtmlParser,这里修改的代码就不贴出来了,有兴趣的朋友可以去:
http://htmlparser.sourceforge.net/
看看。
目前互联网上公布出来的正文提取算法,大家可以综合比较下,一起来测试下哪个更好用。 词网--北京词网科技有限公司 http://demo.cikuu.com/cgi-bin/cgi-contex 猎兔网页正文提取 http://www.lietu.com/extract/ PHP版网页正文提取 http://www.woniu.us/get_content_demo/ 网页正文提取分析(DEMO) http://61.128.196.27/txt 个人认为http://61.128.196.27/txt 这个提取最牛,基本上无论什么页面都能提取出来,而且能有效的保持原文风格、图片、链接。
http://code.google.com/p/joyhtml/
看看这个效果不错
http://www.likeshow.net/article.asp?id=92
我一年前写的玩意 虽然不完善 但尚可用之在新闻和BLOG 论坛提取上 提取的正文对于BLOG和BBS包含评论及回复 具体原理也写很清楚了
如题,想从html源码中提取正文内容,<P></P>之间的内容,但是<P>的写法不规则。除了正则表达式的方法,还有其它的提取方法吗?谢谢!
最新下载
在线演示和最新下载:
http://www.shoula.net/ParseContent
http://www.pudn.com/downloads152/sourcecode/internet/search_engine/detail668443.html
Google Code开源网页正文提取cx-extractor2010-05-19 12:31基于行块分布函数的通用网页正文抽取:线性时间、不建DOM树、与HTML标签无关
简述:
对于Web信息检索来说,网页正文抽取是后续处理的关键。虽然使用正则表达式可以准确的抽取某一固定格式的页面,但面对形形色色的HTML,使用规则处理难免捉襟见肘。能不能高效、准确的将一个页面的正文抽取出来,并做到在大规模网页范围内通用,这是一个直接关系上层应用的难题。
作者提出了《基于行块分布函数的通用网页正文抽取算法》,首次将网页正文抽取问题转化为求页面的行块分布函数,这种方法不用建立Dom树,不被病态HTML所累(事实上与HTML标签完全无关)。通过在线性时间内建立的行块分布函数图,直接准确定位网页正文。同时采用了统计与规则相结合的方法来处理通用性问题。作者相信简单的事情总应该用最简单的办法来解决这一亘古不变的道理。整个算法实现不足百行代码。但量不在多,在法。
项目网址:http://code.google.com/p/cx-extractor/
算法描述:基于行块分布函数的网页正文抽取算法.pdf
欢迎大家提出意见~
http://www.ngiv.cn/post/204.html
VIPS算法对搜索引擎的意义
http://blog.csdn.net/tingya/archive/2006/02/18/601954.aspx
基于视觉的Web页面分页算法VIPS的实现源代码下载
http://blog.csdn.net/tingya/archive/2006/04/28/694651.aspx
作者信息:飞跃,javascript教程-技术之家博客的博主
http://www.madcn.net/?p=791
我这里有个开源的项目,还不错,你上googlecode搜索joyhtml。
http://gfnpad.blogspot.com/2009/11/blog-post.html
下面几个是一些开源的程序:
1.一个python的基于文本密度的程序:
http://ai-depot.com/articles/the-easy-way-to-extract-useful-text-from-arbitrary-html/
ps:里面有bug,要稍加改动。 另外,对于没有对html注释部分进行处理
2.Java 开源项目: Gate
http://gate.ac.uk/
其实可以利用Dhmtl对象进行编程分析,已获得所要的数据文件,详细请看我的程序
http://www.vbgood.com/thread-94788-1-1.html
http://download.csdn.net/source/568439
一.标题块
l 分块节点:td,div,h,span
l 一般位于Head/Title的位置
l 当前单元含有<h1>-<h3>,<b>,<i>,<strong>等标签
l 样式,一般class包含title,head等字符
l 文字长度,一般大于3个字符,小于35个字符
二.发表时间块
l 分块节点:td,div, span
l 文字长度,一般小于50个字符
l 包含日期格式(2010-08-09)的字符串
l 包含以下关键字:来源,发表
三.主题块
l 分块节点:td,div
l HTML网页中有一些特殊标签,通常只出现在网页主题块中,如<P><BR>等。因此,主题块中往往包含着特殊标签。
l 主题块内容含有较多的句子,因此具有较多逗号、句号等标点符号(>5)。
l 若从信息量角度考虑,主题块一般是含有较多文字信息。
l 主题块的 标签密度=1000*标签数/文字数 应在小于一个范围。
l 主题块的 文本密度=len(文本)/len(HTML代码) 较大
l 不应该包含 “上一篇”,“下一篇”
l 包含以下字符串的内容块,判定为包含版权信息,需减权:“ICP备04000001号”,“版权所有”,“Copyright”
l 主题块序号在标题块之下
l 主题块序号在发表时间块之下
l 主题块序号在相关链接块之上
四.相关链接块
l 分块节点:td,div
l 文字应为“相关链接”、“相关新闻”、“相关报道”等敏感词,且连接比例很高。
l 链接数小于20
实现:
根据以上信息块特征,采用特征提权算法,C#(3.5)编程实现,命名为QD正文提取组件。经测试,对Html格式规范的以文字为主的内容页,正确提取率在85%以上,各大门户的新闻页面在95%以上。 例子下载(需要安装Microsoft .NET Framework 3.5)
注:QD正文提取组件 不开源,需要源码的朋友可选择付费获取。
这时挑选出的正文一般也就是到位了,但是问题是很可能在头尾残留了一些块广告。我认为这些块广告与正文中广告有很大的不同。这些广告的马脚就是其父节点,它们的父节点要么也包含了正文所在区域,也就是和正文平级,要么本身就是正文所在区域的一个子节点,很难是正文节点本身的。那么对疑似正文节点进行一次扫描,剔除那些父节点文字内容过大(包含了广告以及正文,即和正文平级)的块,也剔除那些父节点文字内容过小的块。
经过这样的处理,得到的内容基本上就是我们需要的正文了。下面就是要提取标题。
在代表整个网页的document中扫描一次,寻找那些有font字体的,strong的,h1的,title的节点,提取他们的信息。然后将得到的文字内容分词,查验分出来的词有多少是被正文包含的,包含最多的一半就是标题。但是这里要注意,有时候找到的节点本身是正文节点的子节点,那么无论怎么分,分出来都是完全包含的,所以要剔除那些本身是正文一部分的疑似标题。这样做对大部分网页也是有效了,但是对仅有的标题就在正文节点里的那些页面,目前为止我还没有特别好的想法。
这些日子也研究了一些别人的论文,有很多思想都非常好,也有很多人想到用马尔科夫,人工神经来训练。也许以后我会考虑用用看吧。现在这样也还可以,呵呵。
?
这个算法我也写了一下,不过是用C++写的。
我不太懂楼上讨论的分页是什么意思,我通过分析dom树然后用文中提到的规则进行dom结点处理以及后续的处理。
我主要是想把网页中的内容按网页框架分开,把正文部分合在一起,然后用贝叶斯决策计算正文特征支持率
提取网页内容。
现在VIPS基本写完。
但是却也发现了些问题,
比如说有些结点的坐标提取出来会有提取不出分隔条,这是因为有少数坐标有些重叠。这里涉及到一个坐标的确定问题。
然后是结点分割规则问题,现在的页面是大部分是通过DIV来组织页面。而VIPS似乎更合适TABLE组织的页面,我试过用TABLE组织的页面,分得相当不错。
另外,TINYA上面的翻译似乎改了些规则,还有部分翻译不是很准确。比如虚拟文本的定义部分与原文有些出入,不知道TINYA有没有注意到。
最后,很感谢TINYA 对这个算法的介绍。
另外,有对这个算法感兴趣的朋友希望能大家一起讨论下
我的QQ:24888086
msn:[email protected]
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/tingya/archive/2006/02/18/601836.aspx
http://www.hackhome.com/InfoView/Article_119867.html
linux下用valgrind检查程序内存泄漏
问题提出:
如果一个较复杂的程序,有内存泄漏,如何检测?
在windows下,VC本身带有内存泄漏的检查,程序结束时输出窗口会提示有多少memory leaks. linux下有什么办法呢?
1.发现内存泄漏,可以用top或ps。
zhouhh@zhh64:~/smscore$ top | grep firefox
会持续打印firefox的内存占用状况,可以重定向到文件中。
2.静态检测
用splint, PC-LINT,IBM的 BEAM(IBM Checking Tool for Bugs Errors and Mistakes)等。在本文略过。
3.动态检测
有IBM的rational purify,开源的valgrind. 本文主要介绍valgrind。
Valgrind 现在提供多个工具,其中最重要的是 Memcheck,Cachegrind,Massif 和 Callgrind。Valgrind 是在 Linux 系统下开发应用程序时用于调试内存问题的工具。它尤其擅长发现内存管理的问题,它可以检查程序运行时的内存泄漏问题。其中的 memecheck 工具可以用来寻找 c、c++ 程序中内存管理的错误。可以检查出下列几种内存操作上的错误:
* 读写已经释放的内存
* 读写内存块越界(从前或者从后)
* 使用还未初始化的变量
* 将无意义的参数传递给系统调用
* 内存泄漏
valgrind网址:http://valgrind.org/。到现在为止最新版:3.60,支持ubuntu 10.10.对centos 5.2可以直接编译安装使用,ubuntu中遇到一些问题。
3.1下载
zhouhh@zhh64:~/valgrind$ wget http://valgrind.org/downloads/valgrind-3.6.0.tar.bz2
我开始用较老的版本,configure时遇到glibc版本太新的问题。
zhouhh@zhh64:~/valgrind/valgrind-3.4.1$ ./configure
…
checking the GLIBC_VERSION version… unsupported version
configure: error: Valgrind requires glibc version 2.2 – 2.10
我的系统环境:
zhouhh@zhh64:~$ uname -a
Linux zhh64 2.6.35-24-generic #42-Ubuntu SMP Thu Dec 2 02:41:37 UTC 2010 x86_64 GNU/Linux
zhouhh@zhh64:~$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=10.10
DISTRIB_CODENAME=maverick
DISTRIB_DESCRIPTION=”Ubuntu 10.10″
zhouhh@zhh64:~$ ls -l /lib/libc.so.6
lrwxrwxrwx 1 root root 14 2010-11-22 09:58 /lib/libc.so.6 -> libc-2.12.1.sozhouhh@zhh64:~$ ls /lib/libc*
/lib/libc-2.12.1.so
zhouhh@zhh64:~$ /lib/libc.so.6
GNU C Library (Ubuntu EGLIBC 2.12.1-0ubuntu10) stable release version 2.12.1, by Roland McGrath et al.zhouhh@zhh64:~$ gcc -v
Using built-in specs.
Target: x86_64-linux-gnu
gcc version 4.4.5 (Ubuntu/Linaro 4.4.4-14ubuntu5)
下载完成后,解压tar xvf valgrind-3.6.0.tar.bz2,然后configure,编译安装,都没有问题。
zhouhh@zhh64:~/valgrind/valgrind-3.6.0$ ./configure
zhouhh@zhh64:~/valgrind/valgrind-3.6.0$ make
zhouhh@zhh64:~/valgrind/valgrind-3.6.0$ sudo make install
例1.使用未初始化的内存
代码如下
#include <stdio.h>
int main()
{
int x;
if(x == 0)
{
printf("X is zero");
}
return 0;
}
Valgrind提示如下
==14222== Conditional jump or move depends on uninitialised value(s)
==14222== at 0x400484: main (sample2.c:6)
X is zero==14222==
==14222== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 5 from 1)
==14222== malloc/free: in use at exit: 0 bytes in 0 blocks.
==14222== malloc/free: 0 allocs, 0 frees, 0 bytes allocated.
==14222== For counts of detected errors, rerun with: -v
==14222== All heap blocks were freed -- no leaks are possible.
例2.内存读写越界
代码如下
#include <stdlib.h>
#include <stdio.h>
int main(int argc,char *argv[])
{
int len=5;
int i;
int *pt=(int*)malloc(len*sizeof(int));
int *p=pt;
for(i=0;i<len;i++)
{p++;}
*p=5;
printf(“%d”,*p);
return;
}
Valgrind提示如下
==23045== Invalid write of size 4
==23045== at 0x40050A: main (sample2.c:11)
==23045== Address 0x4C2E044 is 0 bytes after a block of size 20 alloc'd
==23045== at 0x4A05809: malloc (vg_replace_malloc.c:149)
==23045== by 0x4004DF: main (sample2.c:7)
==23045==
==23045== Invalid read of size 4
==23045== at 0x400514: main (sample2.c:12)
==23045== Address 0x4C2E044 is 0 bytes after a block of size 20 alloc'd
==23045== at 0x4A05809: malloc (vg_replace_malloc.c:149)
==23045== by 0x4004DF: main (sample2.c:7)
5==23045==
==23045== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 5 from 1)
==23045== malloc/free: in use at exit: 20 bytes in 1 blocks.
==23045== malloc/free: 1 allocs, 0 frees, 20 bytes allocated.
==23045== For counts of detected errors, rerun with: -v
==23045== searching for pointers to 1 not-freed blocks.
==23045== checked 66,584 bytes.
==23045==
==23045== LEAK SUMMARY:
==23045== definitely lost: 20 bytes in 1 blocks.
==23045== possibly lost: 0 bytes in 0 blocks.
==23045== still reachable: 0 bytes in 0 blocks.
==23045== suppressed: 0 bytes in 0 blocks.
==23045== Use --leak-check=full to see details of leaked memory.
例3.src和dst内存覆盖
代码如下
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc,char *argv[])
{ char x[50];
int i;
for(i=0;i<50;i++)
{x[i]=i;}
strncpy(x+20,x,20); //Good
strncpy(x+20,x,21); //Overlap
x[39]=’\0’;
strcpy(x,x+20); //Good
x[39]=40;
x[40]=’\0’;
strcpy(x,x+20); //Overlap
return 0;
}
Valgrind提示如下
==24139== Source and destination overlap in strncpy(0x7FEFFFC09, 0x7FEFFFBF5, 21)
==24139== at 0x4A0724F: strncpy (mc_replace_strmem.c:116)
==24139== by 0x400527: main (sample3.c:10)
==24139==
==24139== Source and destination overlap in strcpy(0x7FEFFFBE0, 0x7FEFFFBF4)
==24139== at 0x4A06E47: strcpy (mc_replace_strmem.c:106)
==24139== by 0x400555: main (sample3.c:15)
==24139==
==24139== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 5 from 1)
==24139== malloc/free: in use at exit: 0 bytes in 0 blocks.
==24139== malloc/free: 0 allocs, 0 frees, 0 bytes allocated.
==24139== For counts of detected errors, rerun with: -v
==24139== All heap blocks were freed -- no leaks are possible.
例4.动态内存管理错误
常见的内存分配方式分三种:静态存储,栈上分配,堆上分配。全局变量属于静态存储,它们是在编译时就被分配了存储空间,函数内的局部变量属于栈上分配,而最灵活的内存使用方式当属堆上分配,也叫做内存动态分配了。常用的内存动态分配函数包括:malloc, alloc, realloc, new等,动态释放函数包括free, delete。
一旦成功申请了动态内存,我们就需要自己对其进行内存管理,而这又是最容易犯错误的。常见的内存动态管理错误包括:
l 申请和释放不一致
由于 C++ 兼容 C,而 C 与 C++ 的内存申请和释放函数是不同的,因此在 C++ 程序中,就有两套动态内存管理函数。一条不变的规则就是采用 C 方式申请的内存就用 C 方式释放;用 C++ 方式申请的内存,用 C++ 方式释放。也就是用 malloc/alloc/realloc 方式申请的内存,用 free 释放;用 new 方式申请的内存用 delete 释放。在上述程序中,用 malloc 方式申请了内存却用 delete 来释放,虽然这在很多情况下不会有问题,但这绝对是潜在的问题。
l 申请和释放不匹配
申请了多少内存,在使用完成后就要释放多少。如果没有释放,或者少释放了就是内存泄露;多释放了也会产生问题。上述程序中,指针p和pt指向的是同一块内存,却被先后释放两次。
l 释放后仍然读写
本质上说,系统会在堆上维护一个动态内存链表,如果被释放,就意味着该块内存可以继续被分配给其他部分,如果内存被释放后再访问,就可能覆盖其他部分的信息,这是一种严重的错误,上述程序第16行中就在释放后仍然写这块内存。
下面的一段程序,就包括了内存动态管理中常见的错误。
#include <stdlib.h>
#include <stdio.h>
int main(int argc,char *argv[])
{ char *p=(char*)malloc(10);
char *pt=p;
int i;
for(i=0;i<10;i++)
{p[i]=’z’;}
delete p;
p[1]=’a’;
free(pt);
return 0;
}
Valgrind提示如下
==25811== Mismatched free() / delete / delete []
==25811== at 0x4A05130: operator delete(void*) (vg_replace_malloc.c:244)
==25811== by 0x400654: main (sample4.c:9)
==25811== Address 0x4C2F030 is 0 bytes inside a block of size 10 alloc'd
==25811== at 0x4A05809: malloc (vg_replace_malloc.c:149)
==25811== by 0x400620: main (sample4.c:4)
==25811==
==25811== Invalid write of size 1
==25811== at 0x40065D: main (sample4.c:10)
==25811== Address 0x4C2F031 is 1 bytes inside a block of size 10 free'd
==25811== at 0x4A05130: operator delete(void*) (vg_replace_malloc.c:244)
==25811== by 0x400654: main (sample4.c:9)
==25811==
==25811== Invalid free() / delete / delete[]
==25811== at 0x4A0541E: free (vg_replace_malloc.c:233)
==25811== by 0x400668: main (sample4.c:11)
==25811== Address 0x4C2F030 is 0 bytes inside a block of size 10 free'd
==25811== at 0x4A05130: operator delete(void*) (vg_replace_malloc.c:244)
==25811== by 0x400654: main (sample4.c:9)
==25811==
==25811== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 5 from 1)
==25811== malloc/free: in use at exit: 0 bytes in 0 blocks.
==25811== malloc/free: 1 allocs, 2 frees, 10 bytes allocated.
==25811== For counts of detected errors, rerun with: -v
==25811== All heap blocks were freed -- no leaks are possible.
例5.内存泄漏
代码如下
#include <stdlib.h>
int main()
{
char *x = (char*)malloc(20);
char *y = (char*)malloc(20);
x=y;
free(x);
free(y);
return 0;
}
Valgrind提示如下
==19013== Invalid free() / delete / delete[]
==19013== at 0x4A0541E: free (vg_replace_malloc.c:233)
==19013== by 0x4004F5: main (sample5.c:8)
==19013== Address 0x4C2E078 is 0 bytes inside a block of size 20 free'd
==19013== at 0x4A0541E: free (vg_replace_malloc.c:233)
==19013== by 0x4004EC: main (sample5.c:7)
==19013==
==19013== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 5 from 1)
==19013== malloc/free: in use at exit: 20 bytes in 1 blocks.
==19013== malloc/free: 2 allocs, 2 frees, 40 bytes allocated.
==19013== For counts of detected errors, rerun with: -v
==19013== searching for pointers to 1 not-freed blocks.
==19013== checked 66,584 bytes.
==19013==
==19013== LEAK SUMMARY:
==19013== definitely lost: 20 bytes in 1 blocks.
==19013== possibly lost: 0 bytes in 0 blocks.
==19013== still reachable: 0 bytes in 0 blocks.
==19013== suppressed: 0 bytes in 0 blocks.
==19013== Use --leak-check=full to see details of leaked memory.
例6.非法写/读
代码如下
int main()
{
int i, *x;
x = (int *)malloc(10*sizeof(int));
for (i=0; i<11; i++)
x[i] = i;
free(x);
}
Valgrind提示如下
==21483== Invalid write of size 4
==21483== at 0x4004EA: main (sample6.c:6)
==21483== Address 0x4C2E058 is 0 bytes after a block of size 40 alloc'd
==21483== at 0x4A05809: malloc (vg_replace_malloc.c:149)
==21483== by 0x4004C9: main (sample6.c:4)
==21483==
==21483== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 5 from 1)
==21483== malloc/free: in use at exit: 0 bytes in 0 blocks.
==21483== malloc/free: 1 allocs, 1 frees, 40 bytes allocated.
==21483== For counts of detected errors, rerun with: -v
==21483== All heap blocks were freed -- no leaks are possible.
例7.无效指针
代码如下
#include <stdlib.h>
int main()
{
char *x = malloc(10);
x[10] = 'a';
free(x);
return 0;
}
Valgrind提示如下
==15262== Invalid write of size 1
==15262== at 0x4004D6: main (sample7.c:5)
==15262== Address 0x4C2E03A is 0 bytes after a block of size 10 alloc'd
==15262== at 0x4A05809: malloc (vg_replace_malloc.c:149)
==15262== by 0x4004C9: main (sample7.c:4)
==15262==
==15262== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 5 from 1)
==15262== malloc/free: in use at exit: 0 bytes in 0 blocks.
==15262== malloc/free: 1 allocs, 1 frees, 10 bytes allocated.
==15262== For counts of detected errors, rerun with: -v
==15262== All heap blocks were freed -- no leaks are possible.
例8.重复释放
代码如下
#include <stdlib.h>
int main()
{
char *x = malloc(10);
free(x);
free(x);
return 0;
}
Valgrind提示如下
==15005== Invalid free() / delete / delete[]
==15005== at 0x4A0541E: free (vg_replace_malloc.c:233)
==15005== by 0x4004DF: main (sample8.c:6)
==15005== Address 0x4C2E030 is 0 bytes inside a block of size 10 free'd
==15005== at 0x4A0541E: free (vg_replace_malloc.c:233)
==15005== by 0x4004D6: main (sample8.c:5)
==15005==
==15005== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 5 from 1)
==15005== malloc/free: in use at exit: 0 bytes in 0 blocks.
==15005== malloc/free: 1 allocs, 2 frees, 10 bytes allocated.
==15005== For counts of detected errors, rerun with: -v
==15005== All heap blocks were freed -- no leaks are possible.
Valgrind的局限
l Valgrind不对静态数组(分配在栈上)进行边界检查。如果在程序中声明了一个数组:
int main()
{
char x[10];
x[11] = 'a';
}
Valgrind则不会警告你,你可以把数组改为动态在堆上分配的数组,这样就可能进行边界检查了。这个方法好像有点得不偿失的感觉。
l Valgrind占用了更多的内存--可达两倍于你程序的正常使用量。如果你用Valgrind来检测使用大量内存的程序就会遇到问题,它可能会用很长的时间来运行测试。大多数情况下,这都不是问题,即使速度慢也仅是检测时速度慢,如果你用Valgrind来检测一个正常运行时速度就很慢的程序,这下问题就大了。 Valgrind不可能检测出你在程序中犯下的所有错误--如果你不检查缓冲区溢出,Valgrind也不会告诉你代码写了它不应该写的内存。
参考文章:
http://www.cnblogs.com/xuybin/p/3166904.html
http://blog.csdn.net/wzzfeitian/article/details/8567030
http://www.ibm.com/developerworks/cn/linux/l-cn-valgrind/
http://www.oschina.net/translate/valgrind-memcheck