申請大量動態記憶體(new/malloc)時 丟擲std::bad_alloc
阿新 • • 發佈:2019-01-01
在申請大記憶體的時候,很可能丟擲std::bad_alloc異常。
為方便檢視,先上解決方案 兩種:
- 修改專案屬性!專案->屬性->配置屬性->連結器->系統,找到”啟用大地址“選項,選擇”是“。
- 將解決方案平臺改成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。
但是,我這個程式挺複雜,還要依賴32位的庫函式,將程式改成64位的代價比價大!
其實,還有一種簡單的方法就是修改專案屬性!
專案->屬性->配置屬性->連結器->系統,找到”啟用大地址“選項,選擇”是“。如下圖:
從圖中可以看見,VS預設應用程式是使用2GB以下的地址的,我程式還有其他的分配空間的地方,所以我粗略測試(載入圖片)只能new 1185M的空間。 測試了一下,自己使用new/malloc分配大記憶體不再出錯;使用OpenCV載入幾十張圖片也不會出錯了! 就這樣,問題輕鬆解決!