[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]