1. 程式人生 > >申請大量動態記憶體(new/malloc)時 丟擲std::bad_alloc

申請大量動態記憶體(new/malloc)時 丟擲std::bad_alloc

在申請大記憶體的時候,很可能丟擲std::bad_alloc異常。

為方便檢視,先上解決方案   兩種:

  1. 修改專案屬性!專案->屬性->配置屬性->連結器->系統,找到”啟用大地址“選項,選擇”是“。
  2. 將解決方案平臺改成64位的。但是可能出現不相容的問題。

比如說:

  • 我最近就需要在跟蹤程式裡面載入50張4K的圖片(3840*2160,BMP格式,23.7MB),總大小超過1GB 
  • 起初我用OpenCV載入圖片,沒有std::bad_alloc錯誤,而是cv::Exception,當時以為是OpenCV自己限制了最多分配多少記憶體的圖片(現在知道我錯了,參見我的另一篇部落格:http://blog.csdn.net/a_txpt_001/article/details/40372497 )
  • 後來我改用C裡面的檔案讀取操作,按照BMP檔案格式,自己讀取圖片,這裡用的是malloc分配空間,最後跟蹤結果是錯的,但是程式沒有報錯!!(WTF!)
    • 我逐步排查,認為只能是讀取圖片錯誤。於是跟進讀取圖片的函式,單步查錯,結果真的發現了貓膩——後面的幾張圖分配空間失敗了!!
    • // LoadBitmapFile
      // desc: Returns a pointer to the bitmap image of the bitmap specified
      //       by filename. Also returns the bitmap header information.
      //		 No support for 8-bit bitmaps.
      unsigned char *LoadBitmapFile(char *filename, BITMAPINFOHEADER *bitmapInfoHeader)
      {
      	FILE *filePtr;								// the file pointer
      	BITMAPFILEHEADER	bitmapFileHeader;		// bitmap file header
      	unsigned char		*bitmapImage;			// bitmap image data
      	int					imageIdx = 0;			// image index counter
      	unsigned char		tempRGB;				// swap variable
      
      	// open filename in "read binary" mode
      	filePtr = fopen(filename, "rb");
      	if (filePtr == NULL)
      		return NULL;
      
      	// read the bitmap file header
      	fread(&bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, filePtr);
      
      	// verify that this is a bitmap by checking for the universal bitmap id
      	if (bitmapFileHeader.bfType != BITMAP_ID)
      	{
      		fclose(filePtr);
      		return NULL;
      	}
      
      	// read the bitmap information header
      	fread(bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, filePtr);
      
      	// move file pointer to beginning of bitmap data
      	fseek(filePtr, bitmapFileHeader.bfOffBits, SEEK_SET);
      
      	// allocate enough memory for the bitmap image data
      	bitmapImage = (unsigned char*)malloc(bitmapInfoHeader->biSizeImage);  // !!這裡會分配失敗!!
      
      	// verify memory allocation
      	if (!bitmapImage)
      	{
      		free(bitmapImage);
      		fclose(filePtr);
      		return NULL;
      	}
      
      	// read in the bitmap image data
      	fread(bitmapImage, 1, bitmapInfoHeader->biSizeImage, filePtr);
      
      	// make sure bitmap image data was read
      	if (bitmapImage == NULL)
      	{
      		fclose(filePtr);
      		return NULL;
      	}
      
      	// swap the R and B values to get RGB since the bitmap color format is in BGR
      	//for (imageIdx = 0; imageIdx < bitmapInfoHeader->biSizeImage; imageIdx+=3)  // 不需要!OpenGL 紋理引數 GL_BGR_EXT就可以簡單實現
      	//{
      	//	tempRGB = bitmapImage[imageIdx];
      	//	bitmapImage[imageIdx] = bitmapImage[imageIdx + 2];
      	//	bitmapImage[imageIdx + 2] = tempRGB;
      	//}
      
      	// close the file and return the bitmap image data
      	fclose(filePtr);
      	return bitmapImage;
      }
      


    • 我想著,malloc我不熟悉,不如換成我熟悉的new。於是,執行一段時間後,就丟擲了std::bad alloc異常。
    • 題外話1——這裡就看出來了用哪種記憶體分配方式好了吧!new會彈出異常,malloc屁都不告訴你一聲,就讓你自個兒找去!!
    • 題外話2——當然了,程式設計高手都有過建議,分配完空間就應該立即檢查是否分配成功,所以對老手來說,這不算啥。但是這可害苦了我這隻菜鳥%>_<%。所以推薦我這樣的菜鳥還是用new來分配空間吧。
    • 題外話3——想看new與malloc的區別,可以參考部落格:http://blog.csdn.net/gc315630/article/details/5833554
    • 繼續,看來兩種分配方式都有分配記憶體的上限啊,這時我也想到原來我採用OpenCV載入圖片彈出的cv::Exception 應該也是因為裡面用到了malloc或者new,而不是OpenCV自身的原因o(╯□╰)o。
那麼,記憶體分配問題到底怎麼解決呢?網上查到一個比較靠譜的解釋說是:““程序分配記憶體過大,網上查閱到單個win32程式程序只能分配1.5-1.6左右記憶體,否則會出現std::bad_alloc錯誤,將程式改成64位即可。”  ”。試著將VS平臺改成x64的確實不再丟擲異常了
但是,我這個程式挺複雜,還要依賴32位的庫函式,將程式改成64位的代價比價大!

其實,還有一種簡單的方法就是修改專案屬性!

專案->屬性->配置屬性->連結器->系統,找到”啟用大地址“選項,選擇”是“。如下圖:


從圖中可以看見,VS預設應用程式是使用2GB以下的地址的,我程式還有其他的分配空間的地方,所以我粗略測試(載入圖片)只能new 1185M的空間。 測試了一下,自己使用new/malloc分配大記憶體不再出錯;使用OpenCV載入幾十張圖片也不會出錯了! 就這樣,問題輕鬆解決!