【问题标题】:Does .Net use Device Dependent or Device Independent Bitmaps?.Net 使用设备相关或设备独立位图吗?
【发布时间】:2010-05-05 03:33:18
【问题描述】:

将图像加载到内存中时,.Net 是否完全使用 DDB、DIB 或其他东西?如果可能,请引用您的来源。

我想知道,因为我们目前有一个经典的 ASP 应用程序,它使用 3rd 方组件加载图像,偶尔会创建“没有足够的存储空间来处理这个命令”。错误。该错误非常不一致,但往往发生在较大的图像上(并非总是如此,但经常发生)。重置 IIS 后,再次处理相同的文件通常可以正常工作。

经过大量研究,我发现 DDB 在处理大图像时往往会出现此问题,因为它们会耗尽视频内存。考虑到我们在带有集成显卡和有限共享内存的 Web 服务器上运行,这肯定是我们的问题。

我们正处于将我们的应用程序转换为 .Net 的早期阶段,并且想知道使用 .Net 是否可能是我们当前方法的可行替代方案,这就是我提出这个问题的原因。

欢迎任何建议 :) 但出于好奇,如果没有别的,我真的希望得到这个问题的答案; .Net 使用 DDB 还是 DIB?

【问题讨论】:

    标签: .net image bitmap


    【解决方案1】:

    免责声明:我的回答可能仅与 WPF 之前的 .NET 相关(但相同的概念适用于两者)。

    标题问题的答案是“两者”。 System.Drawing 命名空间包含一个方便的 Bitmap 类,它本质上是一个 DIB(或设备独立位图)。 Bitmap 类包含一个 GetHbitmap 方法,该方法在内存中创建原始 DIB 的 DDB(或设备相关位图)副本并返回它的句柄。

    可以将 DDB 句柄选择到设备上下文中(这使您可以使用超快的BitBlt API 方法)。或者,您一开始就永远无法创建 DDB,并使用纯 .Net(最好的方法,IMO)来完成所有图形操作。 GetHbitmap 是一种相对危险的方法,因为您必须在它返回的句柄上调用 DeleteObject 以便在完成后释放它的内存(这是我能想到的唯一示例。 需要一个 PInvoked API 调用才能正常运行)。此外,由于该方法返回一个IntPtr,程序员往往没有意识到当它被调用时,操作系统必须开辟另一块大小与原始 .Net (DIB) 位图相等的内存。

    所以答案是:.Net 使用 DIB,但必要时可以使用 DDB。或者更糟糕的是,当不是必要时。实际上,我继承了不止一个使用 GetHBitmap 而没有匹配的 DeleteObject 调用的 .NET Web 应用程序,从而产生了一次长时间的内存泄漏。

    不过,您有一个更广泛的问题,即:在服务器上运行的 .Net 应用程序能否可靠地处理大量大型图像文件而不会导致服务器崩溃?答案是肯定的,只要您真正了解 .NET 框架在幕后通过图像处理做什么。 .NET 图形类封装了许多远离程序员的可怕细节,在某些方面这有点糟糕,因为它使程序员不太可能了解真正发生的事情。

    编辑:忘记包含来自MSDN的重要免责声明:

    注意

    System.Drawing 中的类 不支持使用命名空间 在 Windows 或 ASP.NET 服务中。 尝试使用这些类 在这些应用程序类型之一中 可能会产生意想不到的问题,例如 由于服务性能下降和 运行时异常。

    翻译:“你可能会搞砸这件事 - 不要说我们没有警告过你”。从根本上说,这是一个合理的建议,因为这些类——虽然非常强大和有用——也很危险。消耗一些资源并且无法正确释放它,或者以导致大量内存消耗的方式使用类是非常容易的。有时这些问题在桌面应用程序中并不大,但在同时处理多个请求的负载很重的 Web 服务器中,它可能会成为一个大问题。

    我认为在这种情况下可以安全地使用它们,但是,或者换一种说法,如果您尝试在网络服务器同时。但是,我会确保在投入生产之前对我的网站代码进行了大量负载测试。

    更新1:以下引用(带有link)适用于.NET Compact Framework中的位图,我认为它不适用于完整的框架(我主要包括在这里供一般参考 - 即有一天我可以自己再次找到它):

    这里有一些更深入的信息 [.NetCF] 位图的分配方式。 有两条主要途径 分配可能会影响 内存已分配,但最后 有与指示相同的问题 以上。

    1. 接受流的位图构造函数 作为参数[即从文件加载]
      • 这将构造一个 DIB
      • DIB 被分配到应用程序进程虚拟内存之外 (VM) 地址空间
    2. 位图构造函数 将高度/宽度作为 参数
      • 这将构建一个 DDB
      • DDB 由驱动程序分配,通常在 gwes.exe 或可能 在专用的视频 RAM 中。这会 实际使用物理和虚拟 不在进程 VM 中的内存 空间。

    简而言之,我们有 2 种不同类型的 我们运行时中的位图有不同的 性能和分配 特征。 DDB 通常是 更快地操纵和绘制 屏幕比 DIB,但它们是 在外部存储器中构建 可能导致分配的空间 混乱并导致性能 调用 LockBits 或 Save to be 慢点。如果需要 DIB 并且您 希望根据宽度构建它 和高度,我们提供了一个函数 构造一个具有宽度的位图, 指定的高度和像素格式。 该函数将构造一个 DIB 而不是 DDB。

    更多信息(仍然只是关于 .NetCF 位图):

    http://blog.opennetcf.com/ctacke/PermaLink,guid,987041fc-2e13-4bab-930a-f79021225b74.aspx

    更新 2: 一些与完整框架中的 .NET 位图相关的链接(摘要在底部):

    http://www.dotnetmonster.com/Uwe/Forum.aspx/dotnet-performance/1187/Graphics-FromImage-Process-memory-usage

    http://www.netframeworkdev.com/common-language-runtime/memory-issues-with-systemdrawingbitmap-30879.shtml

    http://www.west-wind.com/WebLog/posts/8230.aspx

    http://www.tech-archive.net/Archive/DotNet/microsoft.public.dotnet.framework.drawing/2005-06/msg00171.html

    总结:我认为这个问题很难回答,因为基本上,这个(Bitmap 使用的内存的实际位置)是一个内部 .NET 实现细节,大部分没有记录在好理由。因为看起来你现在不能确定位图的内存在哪里,而且你肯定不能确定它将来会在哪里,我不得不说 MSDN 可能不是在开玩笑,他们说:

    注意

    System.Drawing 中的类 不支持使用命名空间 在 Windows 或 ASP.NET 服务中。 尝试使用这些类 在这些应用程序类型之一中 可能会产生意想不到的问题,例如 由于服务性能下降和 运行时异常。

    【讨论】:

    • 您能否引用您对 .Net 如何管理图像的参考资料?我无法找到此信息,但它必须在某个地方可用。我想了解更多。
    • “或者,您一开始就永远无法创建 DDB,而使用纯 .Net 执行所有图形操作(最好的方法,IMO)。” -- 安全但安全..................................l................................. o........w
    • 只是为了澄清,这意味着 s....................... .o........w.
    • @Brian:我刚刚重新阅读了您的问题,并意识到我并没有真正回答它。我会在这方面找到一两个参考资料——我自己的知识在 Windows 和 Windows Mobile 之间比较混乱。
    • @Windows 程序员:不是。 :)
    【解决方案2】:

    经过大量研究,我确定尽管 System.Drawing 命名空间不受支持,it will probably work for many people(可能不适合我们,因为我们进行了大量的图像处理)。

    然而,支持的是Windows Imaging Components,但它不是托管代码,尽管它们确实提供了一个围绕 Win32 调用的瘦 .Net 包装器。 Bertrand Le Roy 的博客有一篇关于如何使用它的文章:The fastest way to resize images from ASP.NET. And it’s (more) supported-ish。 WIC 似乎比 GDI+ 快得多。

    Bertrand 还介绍了如何使用 WPF 处理图像,它不受支持,但使用 WIC,似乎与直接 WIC 的性能相当,并且可能更容易编码。文章为:Resizing images from the server using WPF/WIC instead of GDI+

    WIC 和 WPF 都需要完全信任,因此如果您在中等信任环境中工作,您将无法使用 GDI+。

    【讨论】:

    • 如果您处于中等信任环境,您将无法使用unsafe 关键字,该关键字允许通过LockBits 方法直接访问Bitmap 的像素数据,尽管这仅在您尝试进行逐像素操作时才有意义。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-17
    • 1970-01-01
    • 2012-09-17
    • 2021-10-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多