1. 程式人生 > >【VS開發】malloc申請記憶體錯誤分析

【VS開發】malloc申請記憶體錯誤分析

每個程序會有4G的虛擬地址空間, malloc得到的的地址都是虛擬地址, 並且當malloc的時候, 作業系統並不會將實際的記憶體分配給程序的, 所以malloc只會佔用程序自身的虛擬地址空間。
我以前也做過申請記憶體的測試,並且寫了一個短文:

作業系統: Redhat Linux AS5 32bit
伺服器記憶體: 4G
伺服器型別: I32

最近寫搜尋引擎, 因為建立索引需要大量的記憶體, 所以對Linux下的大記憶體申請進行了一些測試.

(1)char * p = (char *)malloc( 2G位元組 );
=>申請失敗.
(2)char * p = (char *)malloc( 1.9G位元組 );

=>申請成功
(3)連續的申請10個300M的記憶體空間
for ( i=0; i<10; i++ )
p = (char*)malloc(300M位元組)
=>前9次成功, 最後1次申請失敗
(4)先申請1.9G, 再申請900M
p = (char *)malloc( 1.9G位元組 );
p = (char *)malloc( 900M位元組 );
=>兩次申請都成功.

我的理解如下:
對於在普通預設的2.6.*的linux核心!
32位的機器裡, 一個程序的記憶體地址空間範圍是0-3G共4個G, 其中最後一個G是核心態的地址空間, 所以給使用者態的記憶體地址空間只留下了前3個G. 那麼這樣, malloc能夠申請到3G以內的記憶體才對, 但是結果並非如此.在(1)中我們申請2G的記憶體都沒有申請到, 這是什麼原因呢?先讓我們看一看實際上程序的4G記憶體空間都放著或被map著什麼:


第0G和第1G:使用者態地址空間
第2G:庫函式對映等
第3G:核心態記憶體空間

使用者態地址空間中還包含了程序程式碼本身佔用的地址空間, 棧的空間等等.
第2G中, 庫函式對映等只佔用了很少的一部分空間,還有很多的空閒空間.

現在讓我們解釋這4個問題:
第(1)個問題, 由上圖可以看出, 沒有連續的2G的記憶體, 所以申請2G的連續記憶體是肯定失敗的.
第(2), 申請1.9G的空間是成功的, 這是因為前兩個G可能會有1.9G的連續空間.
第(3), 申請了300M*9 = 2.7G是成功的, 是的, 前3G中有可能空間著2.7G的空間, 前兩個G中空閒的加上第3個G中空閒的部分. 但是如果一次申請2.7G是不行的, 因為沒有連續的2.7G的地址空間. 最後一個300M沒有申請成功的原因是, 申請的空間大小不能超過3G的使用者態地址空間.

第(4), 比較有意思, 顯然那個1.9G是在第1-2G這個地址空間中申請成功的, 後900M是第3個G這片地址空間中申請成功的. 我們一共申請到了2.8G的"記憶體", 卻也不是連續的

續:

相信C/C++程式設計師都用過這個庫函式, 這個函式時程式設計師申請堆中的記憶體,需要自己手動釋放記憶體,所以這個函式也是Memory Leak的根源。但是malloc一次最多能申請多少記憶體呢,顯然這個跟我們實體記憶體的大小和
我們的系統,編譯器都有一定的關係。已經不記得之前在哪裡遇到過這個問題,今天忽然想起來了,於是自己做了個實驗。
我的開發環境是Windows7 64位,記憶體8G,IDE是codeblocks,支援開源,下面是測試程式碼:

點選(此處)摺疊或開啟

  1. #include <iostream>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. int64_t maximum = 0;
  5. using namespace std;
  6. int main()
  7. {
  8.     cout<<"sizeof(void*) is:"<<(int)sizeof(void*)<<endl;
  9.     cout<<"sizeof(int) is:"<<sizeof(int)<<endl;
  10.     int64_t blocksize[] = {1024*1024, 1024, 1};
  11.     int64_t i, count;
  12. for(i=0;i<3;i++)
  13. {
  14.         maximum = 0;
  15. for(count=1;;count++)
  16. {
  17.                 void *block = (void*)malloc(maximum + blocksize[i] * count);
  18. if(block)
  19. {
  20.                         maximum = maximum + blocksize[i] *count;
  21.                         free(block);
  22. }
  23. else
  24. {
  25.                         break;
  26. }
  27. }
  28.          cout << "maxmium malloc size:"<<maximum/1000000<<"M"<<endl;
  29. }
  30.     cout << "Hello world!" << endl;
  31.     return 0;
  32. }

程式輸出如下:

這個結果是不是很蹊蹺,我64位的系統,而且8G的記憶體,佔用了很少,但是這裡為什麼只分配了2G不到呢,我原來的推想是作業系統保留一部分記憶體(大概2G),還有差不多6G可以申請,所以這個結果讓我很驚訝。於是我又在64bit的linux下,記憶體4G,用同樣程式碼進行了測試,這次輸出是


這次輸出似乎跟預想差不多,4G記憶體能分配3.5G左右,那麼windows下是什麼問題導致我8G的記憶體只能malloc 2G不到呢。細想一下,覺得肯定是編譯器的問題,果然我的codeblocks預設的編譯器是mingw-32-g++,可能細心的讀者已經看到前面的sizeof(void*)的值是4,也就是說在windows下codeblock下預設將該程式編譯成32位的了,所以才會出現分配2G不到的記憶體,感興趣的可以用其他的64位的編譯器測試一下,應該會得到正常值。

總結一下:

程式是32位或者是64位並不是由你的作業系統決定,而是編譯器決定,準確的說是決定於編譯器和編譯選項,64位系統照樣可以跑32位的程式。





相關推薦

VS開發malloc申請記憶體錯誤分析

每個程序會有4G的虛擬地址空間, malloc得到的的地址都是虛擬地址, 並且當malloc的時候, 作業系統並不會將實際的記憶體分配給程序的, 所以malloc只會佔用程序自身的虛擬地址空間。我以前也做過申請記憶體的測試,並且寫了一個短文:作業系統: Redhat Lin

VS開發C/C++開發傳遞雙重指標申請記憶體,典型用法

指標引數是如何傳遞記憶體的? 如果函式的引數是一個指標,不要指望用該指標去申請動態記憶體。如下示例中,Test函式的語句GetMemory(str, 100)並沒有使str獲得期望的記憶體,str依舊是NULL,為什麼? void GetMemory(char *p, int num) {  p = (c

VS開發關於記憶體洩漏的除錯

沒想到造成洩漏的原因是由於儲存資料的執行緒因為事件阻塞在那裡,此時要關閉OnClose的時候,這個掛起的執行緒爆出了記憶體洩漏,所以在關閉視窗之前,需要SetEvent(m_hSaveDataEvent);來把掛起的執行緒啟用,之後的釋放就不再出現記憶體洩漏了。

VS開發Visual Studio 2015 無法解析的外部的符號 __vsnwprintf_s

IDE:Visual Studio 2015 作業系統:win 10   問題: 編譯的時候可能會遇到 ERROR LNK2019:無法解析的外部的符號 __vsnwprintf_s,或者是_sscanf,_sscanf_s等等一系列形如這樣的函式   疑

VS開發/FORCE(強制檔案輸出)

/FORCE:[MULTIPLE|UNRESOLVED] 備註 即使引用了符號但未定義或多次定義符號,/FORCE 選項也通知連結器建立有效的 .exe

VS開發VS編譯時提示"已經在 LIBCMT.lib(new.obj) 中定義uafxcw.lib"解決辦法

  錯誤  1  error LNK2005: "void * __cdecl operator new(unsigned int)" ( [email protected]@Z )

VS開發開發最小化到托盤的功能

在VC++中,想實現最小化MFC程式的時候,最小化到系統托盤,需要呼叫NOTIFYICONDATA類 下面我們就來講解一下如何簡單實現一個系統托盤我們以對話方塊程式為列 第一步:在Dlg類中//定義一個NOTIFYICONDATA類的成員變數,用來設定托盤 NOTIFYIC

VS開發影象處理直方圖均衡與平臺直方圖

首先需要說明的是,如果你說的是一道完整的題目,則這道題目沒有唯一解,因為題目中沒有說明原始影象的灰度級數(比如原始影象是16個灰度級的,或者是32個灰度級的,等等)。為了給你提供一個解題思路,現在人為假設原始影象是16個灰度級的,其它灰度級的解法類似。 1、影象的灰度直方圖求法為: (1)先計算影象中各個灰度

VS開發使用 NuGet 管理專案庫

NuGet 使用 NuGet 管理專案庫 無論多麼努力,Microsoft 也沒辦法提供開發人員所需要的每一個庫。 雖然 Microsoft 在全球的員工人數接近 90,000,但全球的開發人員數以百萬計。 指望 Microsoft 滿足每一個人的需求是不現實的,也不可想像。 因此,開發人員

VS開發MFC執行時庫與debug、release版本之間的配置關係

參考內容:  前段時間從網上下來一個有意思的程式碼,用VS2010開啟時需要將工程轉換為2010的工程,轉化後卻出現了編譯不通過的問題,類似這樣的錯誤:c:\program files\microsoft visual studio 10.0\vc\atlmfc\inc

VS開發影象處理RGB各種格式

RGB格式 RGB組合格式 名字 RGB組合格式 描述 此格式用來匹配PC圖形幀快取。每個畫素佔據8,16,24或32個位,他們都是組合畫素格式,其意為在記憶體中所有畫素資料都是相鄰排列的。當使用這些格式之一時,驅動應該上報顏色空間為V4L2_COLORSPACE_S

VS開發使用CTabView分割多頁卡視窗

一般書中介紹的是使用CSplitterWnd來拆分視窗實現多檢視,CSplitterWnd中的CreateClient可以儲存其建立的pCreateContext指標,以便子檢視共享Document。這我用一篇文章詳細說明。CTabView建立多檢視的好處在於簡單的標籤切

VS開發程序執行緒及堆疊關係的總結

二、堆和棧的理論知識 2.1申請方式 stack: 由系統自動分配。例如,宣告在函式中一個區域性變數 int b; 系統自動在棧中為b開闢空間 heap: 需要程式設計師自己申請,並指明大小,在c中malloc函式 如p1 = (char *)malloc(10); 在C++中用new運算子 如p2 = (c

VS開發熟悉和修改VS2015的常用快捷鍵為eclipse風格!用著舒服!

用習慣了eclipse,平時也會交叉的用一用VS2015。兩個IDE之間的快捷鍵差距實在太大了,有時候經常按錯。無奈之下,只好把VS2015的快捷鍵修改成和eclipse一樣,這樣就省心舒服了!!正常情況下VS2008,VS2010,VS2013,VS2015,VS2017的

VS開發免費打工仔:一個完善的ActiveX Web控制元件教程

作者 David Marcionek. 翻譯 免費打工仔 這個教程可以幫助你快速開發一個ActiveX控制元件。其中將要講解關於ActiveX開發的一些基礎概念,諸如方法(method)、屬性(propertiy)和事件(event),以及ActiveX控制元件和網頁

C/C++開發VS開發win32位與x64位下各型別長度對比

64 位的優點:64 位的應用程式可以直接訪問 4EB 的記憶體和檔案大小最大達到4 EB(2 的 63 次冪);可以訪問大型資料庫。本文介紹的是64位下C語言開發程式注意事項。 1. 32 位和 64 位C資料型別 32和64位C語言內建資料型別,如下表所示:

VS開發C++ opencv Mat基礎

1.Mat基礎 在計算機記憶體中,數字影象是已矩陣的形式儲存的。OpenCV2中,資料結構Mat是儲存影象畫素資訊的矩陣,它主要包含兩部分:矩陣頭和一個指向畫素資料的矩陣指標。 矩陣頭主要包含,矩陣尺寸、儲存方法、儲存地址和引用次數等。 矩陣頭的大小是一個常數,不會隨著影象的大小而改變,但是儲存影象畫素資料

VS開發CTabView多頁卡介面

The CTabView class simplifies the use of the tab control class (CMFCTabCtrl ) in applications that use MFC's document/view architecture. class CT

VS開發OpenGL開發OpenGL---Windows下配置與第一個OpenGL程式

面記錄一下Windows下配置OpenGL與我的第一個OpenGL程式。 第一步:選擇一個編譯環境 現在Windows系統的主流編譯環境有Visual Studio,Broland C++ Builder,Dev-C++等,它們都是支援OpenGL的。但這裡我選擇的是V

VS開發組播(多播)的C程式實戰

每個人都有不同的認知規律和習慣, 有的人喜歡搞一套嚴密的大理論, 論述起來滔滔不絕, 不管自己懂不懂, 反正讀者/聽者是沒搞懂。 有的人喜歡從實踐出發, 沒看到程式碼, 不執行一下, 不看到結果, 就不太舒服。 我感覺, 我偏向後者, 必須有一個結果作用於我, 我才有感觸