申请大量动态内存(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位的代价比价大!

其实,还有一种简单的方法就是修改项目属性!


项目->属性->配置属性->链接器->系统,找到”启用大地址“选项,选择”是“。如下图:


申请大量动态内存(new/malloc)时 抛出std::bad_alloc_第1张图片

从图中可以看见,VS默认应用程序是使用2GB以下的地址的,我程序还有其他的分配空间的地方,所以我粗略测试(加载图片)只能new 1185M的空间。


测试了一下,自己使用new/malloc分配大内存不再出错;使用OpenCV加载几十张图片也不会出错了!

就这样,问题轻松解决!



你可能感兴趣的:(Bug集锦)