【问题标题】:Trying to load 150+ grayscale 4096 x 4096 bitmaps. Need help getting around the 2GB limit, I think尝试加载 150+ 灰度 4096 x 4096 位图。我认为需要帮助绕过 2GB 限制
【发布时间】: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 的虚拟内存,则无法将其全部映射到虚拟内存中

标签: c# winforms


【解决方案1】:

在 64 位操作系统(我猜你是)。一个简单的列表也应该起作用:

    var imageFiles = Directory.EnumerateFiles(@"C:\Temp", "*.bmp", SearchOption.TopDirectoryOnly).ToList();
    var lst = new List<Bitmap>();
    foreach (var imageFile in imageFiles)
    {
        lst.Add(new Bitmap(imageFile));
    }

【讨论】:

  • 谢谢你的代码,迈克,但不幸的是我得到了同样的结果。在 i == 51 时出现 OutOfMemoryException。
  • 仔细检查一下,您的项目设置为为 64 位操作系统构建,而您的操作系统是 64 位的,对吗?
  • 嗯,正如我父亲常说的,“我感觉自己就像一匹北行的马的南端。”我只是假设 Visual Studio 2012 默认构建 64 位应用程序。当我关闭“首选 32 位”时,一切都如我所愿。非常感谢你,迈克!
【解决方案2】:

它们所有是否必须同时加载?您能否加载其中的 20 个,然后在您处理或显示这些时,您有一个后台线程准备接下来的 20 个。

【讨论】:

  • 是的,出于各种原因(性能、图像处理等),它们都必须同时加载到 RAM 中。
猜你喜欢
  • 2016-11-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-11
  • 2019-06-18
  • 2016-04-27
  • 2010-09-16
相关资源
最近更新 更多