检索可用的连续内存

时间:2013-05-22 08:00:19

标签: c# .net memory-management gdi+

我必须生成大胖子大图像,比如15000x3000。我使用GDI +,类Bitmap生成此图像。

当然,有时候,生成将失败,因为没有更多的内存来实例化Bitmap。我的目标是告知用户他们允许生成的图像的最大大小。

该消息应如下所示:

  

您尝试生成大小为15000x3000的图像,但内存不足。   可用的最大大小为10000x3000或15000x1000。

创建消息的想法是这样的:

public bool CanCreateBitmap(Size size, out string message)
{
    long availableMemory = this.GetAvailableContiguousMemory();
    long bytesRequiered = (long)size.Width * size.Height * 32;

    if (availableMemory < bytesRequiered)
    {
        var sizeProposal1 = new Size(size.Width, (int)(availableMemory / (32 * size.Width)));
        var sizeProposal2 = new Size((int)(availableMemory / (32 * size.Height)), size.Height);

        message = string.Format("You tried to generate an image of size {0}, but there is not enough memory."
                + Environment.NewLine + "The maximum size available is {1}, or {2}."
                , size, sizeProposal1, sizeProposal2);

        return false;
    }
    else
    {
        message = "";
        return true;
    }
}

但是我没有函数GetAvailableContiguousMemory()的代码。

是否有方法可以检索.Net中的连续内存?
我是否提出了正确的问题来实现我的目标?

2 个答案:

答案 0 :(得分:3)

没有这样的功能,因为问题“我可以分配多少内存”包含竞争条件。假设存在您需要的功能并且您调用它并且它告诉您存在大量可用内存。您将该信息传达给用户,用户决定图像大小,然后您开始实际分配图像。但是其他一些进程占用了一半的可用内存,现在你的调用因OutOfMemoryException而中断。

TCP / IP上的媒体流存在类似的问题。您希望开始流式传输视频,但它需要相当多的网络带宽,并且您希望确保此带宽在几分钟之后也可用,因为启动视频流只会产生相反的效果。当播放达到视频长度的三分之二时卡住。现在,通过在握手阶段保留网络资源解决了这个问题 - 即使您现在没有使用带宽(视频流还没有开始)。

好吧,您可能会尝试使用一些模糊的Windows API调用来实现类似的效果。尝试从VirtualAlloc函数开始研究。但是,我不建议您走这条路,因为您的应用程序即使您运行良好,也可能不稳定或不可靠或影响系统上的其他进程。特别是,这些Windows API本身是从C ++使用的,你在.NET中使用托管堆 - 我没有尝试过这样的方法,也无法预测结果(但是如果你成功了,我想听听你的结果! )。

您要问的是设计决策。我还建议使用dandan78的方法 - 让用户选择图像大小,尝试创建它并在尝试失败时传回错误。用户最终会习惯于他们的计算机能力,并且不会经常将系统推到极限之外。

编辑:你应该记住的另一件事:没有“可用的连续记忆”这样的东西。操作系统为您提供虚拟内存页面。然后在引用时将这些页面加载到内存中。如果你要求大量内存,你会得到一堆页面,这些页面将在虚拟内存空间中分配连续的地址,这就是你会得到内存连续的印象。但是,您通常会在new语句返回非连续的内存位置,因为内存管理器只返回托管堆上的第一个可用插槽。我知道这些问题不适用于这个问题,但在这样的情况下,记住内存管理策略肯定不会受到伤害。

答案 1 :(得分:3)

这种通知是一种实际上并没有帮助用户的创可贴。他们真的想要创建那个大位图,而任意小的位图并不是他们想要的。如果你想要这样做,那么你需要调整VirtualQuery来遍历虚拟地址空间并找到尚未映射的块。

现在不再有这个问题,将项目的平台目标设置更改为AnyCPU,这样您的程序就可以使用64位操作系统上可用的虚拟内存空间了。