[Powered by Google Translate] [Valgrind的]
[内特 - 哈迪森，哈佛大学]
这是CS50，CS50.TV]
在C程序中最困难的错误
来自管理不善的内存。
有数量庞大的方式来搞砸了，
包括分配错误的内存量，
忘记初始化变量，
写入结束之前或之后，缓冲液，
和释放内存保持多次。
症状的范围从间歇性崩溃
神不知鬼不觉覆盖值，
往往是在远离原来的错误的地点和时间。
追踪观察到的问题的根本原因
可以是具有挑战性的，
但幸运的是有一个有用的程序，称为Valgrind的
，可以做很多事情来帮助。
>> 您在Valgrind下运行的程序，使
堆内存分配和访问的广泛的检查。
Valgrind的检测到问题时，它可以让你即时，
直接的信息，让您
更容易地找到和解决问题。
在Valgrind也不太致命的内存问题的报告，
如内存泄漏，堆内存分配，
忘记释放它。
像我们的编译器，铛，在我们的调试器，GDB，
Valgrind是，它是免费软件，安装在设备上。
Valgrind的上运行的二进制可执行文件，
不是你的C或H源代码文件，
所以要确保你已经编译到你的程序的最新副本
铛或制作。
然后，在V​​algrind下运行您的程序可以
作为，只是前缀的标准程序命令字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]