【发布时间】:2013-03-06 07:36:20
【问题描述】:
已解决:我错误地认为 Visual Studio 2012 在创建新项目时默认构建 64 位应用程序。在“解决方案属性”的“构建”选项卡下,有一个标记为“首选 32 位”的复选框。当我取消选中此复选框并重建我的解决方案时,我能够一次加载和处理 200 多个位图。感谢 Mike Trusov 如此礼貌地向我指出解决方案。
原始问题:我遇到了一个小问题。我有超过 150 个灰度位图,我想在 8 GB 系统上加载到 RAM 中,但如果不抛出异常,我似乎无法超过 50 个左右。我已经尝试将位图加载到一个数组中,这当然是一个失败的原因,因为 .NET 有 2GB 的限制。但它在加载 2GB 的位图之前很久就失败了。所以我尝试将它们加载到List<List<Bitmap>> 中,但即使这样也失败了。在异常发生时,任务管理器说我有 3939 MB 的可用 RAM 等待填充。很奇怪。
我不需要这些位图在 RAM 中是连续的。对于我所关心的,它们可以是分散的 16 MB 分配。我只想能够用一堆位图填充可用的 RAM。就是这样。
该异常在不同时间是 OutOfMemory 异常或 ArgumentException,具体取决于我启动程序时有多少可用 RAM。在任何一种情况下,堆栈跟踪都会在System.Drawing.Bitmap..ctor(String filename) 中消失。发生异常时正在加载的特定文件没有任何问题。事实上,当我让它加载一组不同(甚至重叠)的位图时,错误会发生在同一次迭代中。
有没有人知道他们可以借给我如何做到这一点?我是否以某种奇怪的方式遇到了 .NET 2GB 的限制?
回答几个问题和 cmets:我在具有 8 GB RAM 的计算机上使用 Visual Studio 2012、.NET 4.5、64 位 Windows 7。是的,出于各种原因(性能、图像处理原因等),我同时需要 RAM 中的所有这些位图。我曾考虑过使用 gcAllowVeryLargeObjects,但我不需要或不希望我的所有位图都放在一大块连续的内存中。我宁愿每个位图都使用自己单独的内存分配。此外,如果我有一台具有 64 GB RAM 的机器,那么即使限制为 150 个这种大小的位图也是荒谬的。为什么不抛出 OutOfMemoryException 就无法加载这些位图?
对我来说,.NET 似乎试图将所有位图保存在一个 2 GB 的区域中。如果有办法让每个位图(这里说的比我知道的更多)都有自己独立的地址空间,那可能会解决问题。为了调用很久以前的 MS-DOS 语言,我想使用长指针分配和访问远内存,而不是将所有数据卡在一个近段中。
数组代码如下:
List<String> imageFiles; // List of .bmp filenames.
Bitmap[] bmps = new Bitmap[100]; // Stores/accesses the Bitmaps.
private void goButton_Click(object sender, EventArgs e)
{
int i;
// Load the bitmaps
if (bmps[0] == null)
{
// Load the list of bitmap files.
imageFiles = Directory.EnumerateFiles(@"C:\Temp", "*.bmp", SearchOption.TopDirectoryOnly).ToList();
// Read bitmap files
for (i = 0; i < bmps.Length; ++i)
{
bmps[i] = new Bitmap(imageFiles[i]); // <-- Exception occurs here when i == 52 or so.
}
}
}
这里是列表>代码:
List<String> imageFiles; // List of .bmp filenames.
List<List<Bitmap>> bmps = new List<List<Bitmap>>(100); // Stores/accesses the Bitmaps.
private void goButton_Click(object sender, EventArgs e)
{
int i;
// Load the bitmaps
if (bmps.Count == 0)
{
// Load the list of bitmap files.
imageFiles = Directory.EnumerateFiles(@"C:\Temp", "*.bmp", SearchOption.TopDirectoryOnly).ToList();
// Read bitmap files
for (i = 0; i < 100; ++i)
{
// Load the bitmap into temporary Bitmap b.
Bitmap b = new Bitmap(imageFiles[i]); // <-- Exception occurs here when i == 52 or so.
// Create and add a List<Bitmap> that will receive the clone of Bitmap b.
bmps.Add(new List<Bitmap>(1));
// Clone Bitmap b and add that cloned Bitmap to the Bitmap of List<Bitmap>.
bmps[i].Add((Bitmap)b.Clone());
// Dispose Bitmap b.
b.Dispose();
}
}
}
【问题讨论】:
-
这个问题和答案可能会有所帮助 - stackoverflow.com/questions/6819606/… - 您运行的是 32 位操作系统吗? 32 位的另一个示例和可能的解决方法 - stackoverflow.com/questions/1109558/…
-
一个可能的选项,gcAllowVeryLargeObjects。 msdn.microsoft.com/en-us/library/hh285054%28v=vs.110%29.aspx
-
不确定这是否与问题有关...但为什么要 a) 制作列表列表,b) 为什么要克隆 bmp 而不是按原样添加到您的列表中,并且 c) 您可以一次只处理一张图像吗?
-
RAM 无关紧要。人们似乎认为 RAM 是内存;几十年来,RAM 都不是内存。请记住,内存现在是虚拟化的; RAM 只是一种使虚拟内存运行得更快的机制。您用完的相关资源是虚拟地址空间,在 32 位操作系统上每个进程限制为 2GB。 内存 使用不受可用 RAM 或可用 VM 空间的限制;您可以为每个进程分配数万亿字节,如果您只有 2GB 的虚拟内存,则无法将其全部映射到虚拟内存中。