Tip:
Highlight text to annotate it
X
[Powered by Google Translate] [Valgrind的]
[内特 - 哈迪森,哈佛大学]
这是CS50,CS50.TV]
在C程序中最困难的错误
来自管理不善的内存。
有数量庞大的方式来搞砸了,
包括分配错误的内存量,
忘记初始化变量,
写入结束之前或之后,缓冲液,
和释放内存保持多次。
症状的范围从间歇性崩溃
神不知鬼不觉覆盖值,
往往是在远离原来的错误的地点和时间。
追踪观察到的问题的根本原因
可以是具有挑战性的,
但幸运的是有一个有用的程序,称为Valgrind的
,可以做很多事情来帮助。
>> 您在Valgrind下运行的程序,使
堆内存分配和访问的广泛的检查。
Valgrind的检测到问题时,它可以让你即时,
直接的信息,让您
更容易地找到和解决问题。
在Valgrind也不太致命的内存问题的报告,
如内存泄漏,堆内存分配,
忘记释放它。
像我们的编译器,铛,在我们的调试器,GDB,
Valgrind是,它是免费软件,安装在设备上。
Valgrind的上运行的二进制可执行文件,
不是你的C或H源代码文件,
所以要确保你已经编译到你的程序的最新副本
铛或制作。
然后,在Valgrind下运行您的程序可以
作为,只是前缀的标准程序命令字Valgrind的简单,
启动Valgrind和它内部的运行程序。
当启动时,Valgrind做一些复杂的
拉坯配置的内存检查的可执行文件,
因此,它可以采取一个位来启动和运行。
然后程序将正常执行,无论是速度要慢得多,
当它完成时,Valgrind会打印出其内存使用的摘要。
如果一切顺利的话,它会是这个样子:
在这种情况下,。/ clean_program
我想运行的程序的路径。
而这一个不带任何参数,
如果它这样做,我只是粘性他们像往常一样到最后的命令。
清洁程序仅仅是一个愚蠢的小程序,我
的整数块在堆中分配空间,
放一些数值,并释放内的整个块。
这是你拍摄的,没有错误,没有泄漏。
>> 另一个重要的指标是分配的字节数。
根据程序,如果你分配在MB或更高,
你可能做错了什么。
你不必要的存储重复?
您是否使用的堆的存储时,它会更好地使用堆栈?
因此,内存错误可能是真正的邪恶。
更加明显的导致壮观的崩溃,
但即便如此,它仍然是很难确定
究竟是什么导致系统崩溃。
更阴险的是,一个程序,一个内存错误
仍然可以编译
似乎仍然可以正常工作
因为你得到幸运的大部分时间。
经过多次“成功的结果,”
你可能认为,事故是侥幸的计算机,
但电脑是永远不会犯错。
>> 运行Valgrind的可以帮助你追踪可见的内存错误的原因
以及潜伏的错误,你甚至不知道的问题。
每次Valgrind的检测到问题时,它打印信息观察。
每一个项目是相当简洁 -
违规指令的源代码行,是什么问题,
和一点点的信息所涉及的内存 -
但往往是足够的信息来将你的注意力到正确的位置。
下面是一个例子,Valgrind的运行在一个错误的程序
做一个无效的读取的堆内存。
我们看到,在编译没有错误或警告。
嗯,哦,说有两个错误错误摘要 -
两个无效的读取大小为4 - 字节,也就是。
这两种坏的读取发生在主函数中的invalid_read.c,
首先在第16行和第19行的第二个。
让我们来看看在代码中。
看起来像调用printf试图读取一个int过去的结束我们的内存块。
如果我们回头看Valgrind的输出,
我们看到,正是Valgrind的告诉我们。
地址,我们尝试读取0字节开始
过去的结束的块的大小为16个字节 -
4个32位的int值分配。
也就是说,我们试图读取的地址块结束时,我们的开始,
正如我们看到在我们的坏printf调用。
现在,无效的读操作可能看起来不是那么大的交易,
但如果您使用的这些数据来控制你的程序的流量 -
例如,语句或循环的一部分,如果 -
接下来的事情可以静静地走坏。
观看如何我可以运行invalid_read的程序
并没有什么不寻常的发生。
可怕的,是吧?
>> 现在,让我们来看看一些更种在你的代码中的错误,你可能会遇到的,
我们会看到它们是如何Valgrind的检测。
我们刚刚看到一个例子,一个invalid_read,
所以现在,让我们看看一个invalid_write。
同样,没有编译错误或警告。
好了,Valgrind的说,在这个程序有两个错误 -
和invalid_write和invalid_read。
让我们来看看这段代码。
看起来我们已经有了一个实例,经典的strlen加一个错误。
该代码不malloc的一个额外的字节的空间
/ 0个字符,
所以,当STR复制去把它写在ssubstrlen“CS50岩石!”
过去我们的块写1个字节。
该invalid_read时,我们使我们调用printf。
printf的阅读无效的内存时,它会读取/ 0个字符
因为它看起来在这个E弦的印刷。
但没有逃脱Valgrind的。
我们可以看到,它抓住了invalid_write的STR副本
在第11行的主,和invalid_read的printf。
岩石上时,Valgrind。
同样,这可能似乎不是什么大不了的。
一遍又一遍以外的Valgrind的,我们可以运行这个程序
并没有看到任何错误症状。
>> 然而,让我们来看看在这方面的一个细微的变化看
如何可以得到非常糟糕的。
所以,理所当然的,我们是在滥用事情变得更不仅仅是一个位在这段代码中。
我们只在堆上分配空间的两个字符串
长度的CS50岩石,
这个时候,记住/ 0字符。
但后来我们扔在一个超长字符串的内存块
S是指向。
什么样的影响会有多大的内存块的T点?
那么,如果T指向的内存就到S相邻,
后,
然后我们可能已经写了一部分,T.
让我们运行此代码。
看看发生了什么事。
在我们的堆块存储的字符串,我们似乎已经正确地打印出来。
似乎没有错。
然而,让我们重新回到我们的代码和
注释掉该行复制CS50岩石
到第二存储器块,指出由t。
现在,当我们运行此代码时,我们应该
只看到第一个内存块的内容打印出来。
哇,即使我们没有STR副本
任何字符到第二堆块,一个由T,
我们得到了一个打印出来。
事实上,字符串,我们塞进我们的第一个块
冲出第一数据块和到所述第二块,
一切似乎正常。
Valgrind的,尽管告诉我们真实的故事。
我们走吧。
所有那些无效的读取和写入。
>> 让我们来看看另一种错误的一个例子。
在这里,我们做的东西,而不幸的。
我们抓住一个int的堆空间,
我们初始化一个int - P - 指针指向该空间。
然而,当我们的指针被初始化,
的数据,它指向的只是垃圾是在这部分的堆。
所以,当我们加载的数据转换成int我,
我们在技术上初始化i,
但我们这样做,用垃圾数据。
调用断言,这是一个方便的调试宏
适当命名的断言库中定义的,
将中止该程序,如果它的测试条件失败。
也就是说,如果不为0,i是。
根据是什么的堆空间,p指向的,
这个程序可能会工作,有时并未能在其他时间。
如果一切正常,我们只是幸运。
编译器不会捕获这个错误,但Valgrind的肯定会。
在那里,我们看到从我们使用的垃圾数据所产生的误差。
>> 当您分配的堆内存,但不释放或释放,
被称为泄漏。
对于一个小的,短命的运行的程序,并立即退出,
泄漏是相当无害的,
但对于较大的尺寸和/或寿命的项目,
即使是很小的泄漏可以复合成一些重大。
CS50,我们希望你
照顾释放所有你分配的堆内存,
因为我们希望您建立的技能,要妥善处理好手工工艺
所要求的C.
要做到这一点,你的程序应该有一个确切的
一对malloc和free调用之间的对应关系。
幸运的是,Valgrind可以帮助你的内存泄漏。
这里是有漏洞的程序,称为leak.c分配
在堆上的空间,写入,但不将其释放。
我们编译它的品牌和在Valgrind下运行,
我们可以看到,虽然我们没有内存不足的错误,
我们确实有一个泄漏。
有16字节绝对丢失,
这意味着该内存的指针是不在范围之内,当程序退出。
现在,Valgrind的不给我们的信息泄漏一吨,
但如果我们按照这个稍微注意一下,它提供了对底部的报告
重新运行 - 泄漏检查全
泄漏的内存的全部细节,
我们会得到更多的信息。
,在堆中摘要,
Valgrind的告诉我们,失去了最初分配的内存。
正如我们知道在源代码中,
Valgrind的告诉我们,我们的内存泄露
leak.c的第8行上调用malloc分配
在主函数中。
相当漂亮的。
>> Valgrind的泄漏使用这些术语进行分类:
绝对迷路 - 这是堆分配内存
程序不再具有一个指针。
Valgrind的都知道,你曾经有过的指针,但已失去了它的轨道。
绝对是这个内存泄露。
间接失去了 - 这是堆分配内存
其中唯一的指针,它也被丢失。
例如,如果你失去了你一个链表的第一个节点的指针,
然后第一个节点本身肯定会被丢失,
而会间接失去了任何后续节点。
可能丢失 - 这是堆分配内存
Valgrind可以无法确定是否有一个指针或不。
仍可达堆分配内存
该程序仍然在出口处有一个指针,
这通常意味着一个全局变量指向它。
要检查这些泄漏的,你还必须包括选项
- 仍可达=
在你调用Valgrind的。
>> 这些不同的情况下,可能需要不同的策略来清理它们,
但泄漏应该被淘汰。
不幸的是,固定泄漏是很难做到的,
因为不正确的电话免费的,可以吹你的程序。
例如,如果我们看invalid_free.c,,
我们看到坏的内存释放的一个例子。
什么应该是一个单一的通话,释放的整个块
的内存的int_block,
如今却成为释放每一个int大小的部分
单独的存储器。
这将失败灾难性的。
轰!什么是错误。
这肯定是不好的。
如果你坚持这样的错误,虽然,你不知道去哪里找,
回到属于你最好的朋友。
你猜对了 - Valgrind的。
Valgrind的,总是知道到底是什么了。
alloc和自由的计数不匹配。
我们已经拿到了1 alloc和释放。
和Valgrind也告诉我们,其中第一个坏的免费电话 -
一个触发的爆破 - 来自 -
线16。
正如你看到的,不好的呼叫释放是非常糟糕的,
因此,我们建议让你的程序泄漏
当你的工作获得正确的功能。
后,才开始寻找泄漏你的程序工作正常,
没有任何其他的错误。
>> 而这一切,我们已经有了这个视频。
你还等什么呢?
转到现在对您的程序运行Valgrind的。
我的名字是Nate哈迪森。这是CS50。 [CS50.TV]