1. 程式人生 > >程式設計:編譯 50 位元組程式碼耗費 4G 記憶體

程式設計:編譯 50 位元組程式碼耗費 4G 記憶體

Valve 工程師 Bruce Dawson 寫了一個大小僅為50位元組的程式,成功使 Visual Studio 的 C++ 編譯器申請了 4GB 記憶體,並最終造成卡死狀態。通過分析編譯過程中記憶體的分配使用情況,Bruce 試圖弄清造成這種狀況的原因,並已將該問題提交給 VC++ 團隊。

想用巨集和內聯彙編做些邪惡的事情(僅僅試著做一些怪異的測試,目的無關緊要),我決定寫個程式讓Vistual Studio的C++編譯器分配4GB的記憶體,然後處於卡死狀態。

寫個50位元組的程式碼就可以了。

一開始我可能沒注意到我的機子並沒有4GB的空閒記憶體,瘋狂的資料分頁,需要找到4GB的記憶體,使得我的筆記本在幾分鐘內都毫無反應。如果你的機子有超過4GB的空閒記憶體,使用ETW做記憶體分析倒是個很好的測試,看看你可以復現我的結果嗎?

我簡化了程式碼,只留下的最基本的精華部分,只是覺得這樣很好玩:

void test()

{

    __asm { add eax

    __asm { add eax

}

這是編譯器的輸出:

error C2414: illegal number of operands

error C2414: illegal number of operands

error C2400: inline assembler syntax error in ‘opcode’; found ‘end of file’

fatal error C1060: compiler is out of heap space

有興趣學習交流c/c++的小夥伴可以加群:941636044

我是在Windows 64位上執行的,編譯器是32位的大型地址程序,所以堆空間耗盡意味著分配大約4GB的記憶體空間。我連續進行多次編譯,可以看出每次4GB的記憶體使用量都在飆升。

我很好奇,到底是哪部分編譯程式在分配這些記憶體。我使用cl.exe編譯器,用etwheap.bat記錄了所有的堆空間和VirtualAlloc 分配 ,並再次編譯了原始檔。事實證明我本應該使用wprui’s VAlloc Usage選項去獲取追蹤。僅僅只有幾MB是從堆上分配的,大部分都是使用VirtualAlloc來分配的,如圖所示:

接下來,為了完成調查,我查看了所有的呼叫棧。我們可以看到內聯彙編程式的語法分析器正在使用它自己的VirtualHeap分配大量的Asm Tokens。VirtualHeap::Create 預留記憶體空間,VirtualHeap::HeapExtend提交記憶體。再深入研究下(沒有顯示)發現記憶體空間預留在512KB的記憶體塊,被提交在32KB的記憶體塊。

還有一些細節,不是很清楚,像為什麼VirtualHeap::HeapExtend呼叫 VirtualHeap::Create,但是卻沒有原始碼,難以得知。

所以我們不再探究了,我像往常一樣將把這個問題提交給VC++團隊。如果他們解決了這個問題,我並不驚訝,這也算不上是一個嚴重的問題。第一次遇到這個問題時,因為我的機子沒有4GB的空閒記憶體,所以才注意到它。

編譯器是32位程序也是件好事兒,要不然它還會繼續消耗記憶體,將遠遠超過4GB。條件限制萬歲!

這些測試都是在VC++ 2010 的除錯版本上進行的,我沒試過其他版本。

Linux 變體

還有一個很類似的問題(連結器在一個很簡單的程式上消耗了大量記憶體,詳情見 棧溢位)。

Windows 糟透了?

我預料到有人會說Windows太爛了,這就是為什麼當遇到這個問題時,我的筆記本幾分鐘內都毫無反應。但是如果在Linux和OSX系統上分配(或寫入)4GB的記憶體,並不會引發嚴重的系統延遲問題,但其實這說明不了什麼。我的筆記本只有8GB的記憶體,大部分都在被使用,想獲取到空閒的4GB記憶體的唯一可能的辦法就是把大量的資料寫到磁碟上。筆記本的硬碟相當慢,如果我是在工作機子上(32GB的記憶體,20GB可用)或者當筆記本上只有很少的程式在執行時(5GB空閒記憶體),做同樣的測試,4GB記憶體的分配和釋放不到5秒中就可以完成。

Reddit的討論連結在這兒

額外補充

很奇怪,怎麼會有一些部落格文章比其他人的更受歡迎…

有人在復現這個問題時遇到了困難,這個bug只能確定在VS2010 SP1 出現,並且test函式放在原始檔的最後。

這顯然不是一個嚴重的bug—程式碼也有缺陷,編譯器有給出了警告並且指出問題所在,也沒出現什麼大問題。但是它的確是一個失敗的詞法分析程式。尤其是,記憶體不足會阻止VC++去報告一些括號不匹配的問題—假如你在test函式之後再新增一個函式,詞法分析完成後,額外的警告就會顯示出來了。

編譯錯誤程式碼時給出出錯的資訊提示是很重要的,這也是Clang的顯式設計目標之一

 

伯樂線上補充:昨天我們發微博釋出這條簡訊後,@棉花糖啊棉花糖o_o成功在 Visual Studio SP1 中復現這個 Bug 了。見下圖或檢視原圖

最後,有興趣學習交流c/c++的小夥伴可以加群:941636044

注:本文轉載自:http://blog.jobbole.com/46106/#article-comment,僅供大家閱讀,希望大家有所         收穫!