.Net 使用设备相关位图还是设备无关位图?

发布于 2024-08-31 11:48:32 字数 439 浏览 5 评论 0 原文

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

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

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

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

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

When loading an image into memory, does .Net use DDB, DIB, or something else entirely? If possible, please cite your sources.

I'm wondering because we currently have a classic ASP application that is using a 3rd party component to load images that is occasionally creating a “Not enough storage is available to process this command.” error. The error is very inconsistent but tends to happen on larger images (not always, but often). After resetting IIS, processing the same file again typically works just fine.

After much research I have found that DDBs tend to have this problem when processing large images because they work out of video memory. Considering that we are running on a web server with an integrated video card and limited shared memory, this could certainly be our problem.

We are in the early stages of converting our app to .Net and am wondering if using .Net for this might be a viable alternative to our current method which is why I am asking the question.

Any advice is welcome :) but out of curiosity if nothing else, I am really hoping for an answer to the question; does .Net use DDB or DIB?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

流心雨 2024-09-07 11:48:32

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

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

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

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

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

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

注意

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

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

我认为它们可以在这种情况下安全地使用,但是,或者换句话来说,如果您尝试在 Web 服务器上处理大量相当大的位图,我认为它们可以像其他任何东西一样安全地使用同时。但是,我会确保在投入生产之前对我的网站代码进行了大量的负载测试。

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

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

  1. 采用流的位图构造函数
    作为参数[即从文件加载]

    • 这将构造一个 DIB
    • DIB 是从应用程序进程虚拟内存中分配的
      (VM)地址空间
  2. 位图构造函数
    其高度/宽度为
    参数

    • 这将构造一个 DDB
    • DDB 由驱动程序分配,通常在 gwes.exe 中或可能在
      在专用视频 RAM 中。这将
      实际使用物理和虚拟
      不在进程VM中的内存
      空间。

简而言之,我们有两种不同类型的
位图在我们的运行时具有不同的
绩效与分配
特征。 DDB 一般是
更快地操纵和绘制
屏幕比 DIB 多,但它们是
在外部存储器中构建
可能导致分配的空间
混乱并导致性能
对 LockBits 或 Save 的调用
慢点。如果需要 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 服务中。
尝试使用这些类
在这些应用程序类型之一中
可能会产生意想不到的问题,例如
由于服务性能下降和
运行时异常。

Disclaimer: my answer is possibly relevant only to pre-WPF .NET (but the same concepts apply to both).

The answer to your headline question is "both". The System.Drawing namespace includes a handy Bitmap class that is essentially a DIB (or Device Independent Bitmap). The Bitmap class includes a GetHbitmap method which creates a DDB (or Device Dependent Bitmap) in-memory copy of the original DIB and returns a handle to it.

The DDB handle can be selected into a device context (which lets you use the super-fast BitBlt API method). Or you can just never create a DDB in the first place, and do all of your graphics operations with pure .Net (the best way, IMO). GetHbitmap is a relatively dangerous method, as you have to call DeleteObject on the handle it returns in order to free up its memory when you're done with it (it's the only example I can think of where a .Net method requires a PInvoked API call in order to function correctly). Also, because the method returns an IntPtr, programmers tend not to realize that when it's called the OS has to carve out another chunk of memory equal in size to the original .Net (DIB) bitmap.

So the answer is: .Net uses DIBs, but can use DDBs if necessary. Or worse, when not necessary. I've actually inherited more than one .NET web app that used GetHBitmap without the matching DeleteObject call, producing one long memory leak.

You have a broader question, though, which is: can a .Net application running on a server reliably process a large volume of large image files without crashing the server? The answer is yes, so long as you really understand what the .NET framework is doing under the hood with image manipulation. .NET graphics classes encapsulate a lot of the grisly details away from the programmer, and some ways this is kind of bad because it makes it less likely that a programmer will learn what's really going on.

Edit: forgot to include this important disclaimer from MSDN:

Caution

Classes within the System.Drawing
namespace are not supported for use
within a Windows or ASP.NET service.
Attempting to use these classes from
within one of these application types
may produce unexpected problems, such
as diminished service performance and
run-time exceptions.

Translation: "you're probably going to screw this up - don't say we didn't warn you". It's fundamentally sound advice, because these classes - while very powerful and utile - are also dangerous. It's extremely easy to consume some resource and fail to release it properly, or to use the classes in a way that results in massive memory consumption. Sometimes these problems are not large in a desktop application, but in a heavily-loaded web server serving multiple requests simultaneously it can become a huge problem.

I think they can be used safely in this context, however, or to put it a little differently, I think they can be used as safely as anything else if you're trying to process a large number of sizable bitmaps on a web server at the same time. However, I would make certain that I heavily load-tested my web site code before going live to production.

Update 1: The following quote (with link) applies to bitmaps in the .NET Compact Framework, and I do not think it applies to the full framework (I'm mainly including it here for general reference - i.e. so I can find it again myself someday):

Here is a little deeper information on
the way [.NetCF] Bitmaps may be allocated.
There are two major paths for
allocation which may affect where the
memory is allocated, but in the end
have the same issues as indicated
above.

  1. Bitmap constructor that takes a stream
    as a parameter [i.e. loads from a file]

    • This will construct a DIB
    • DIBs are allocated out of the application process virtual memory
      (VM) address space
  2. Bitmap constructor
    that takes a height/width as
    parameters

    • This will construct a DDB
    • DDBs are allocated by the driver, typically, in the gwes.exe or possibly
      in dedicated video RAM. This will
      actually use physical and virtual
      memory that is not in the process VM
      space.

In short, we have 2 different types of
Bitmap in our runtime with varying
performance and allocation
characteristics. DDBs are generally
faster to manipulate and draw to the
screen than DIBs, but they are
constructed in an external memory
space that can cause allocation
confusion and cause the performance of
calls to LockBits or Save to be
slower. If a DIB is desired and you
wish to construct it based on width
and height, we provide a function that
constructs a Bitmap with a width,
height, and pixelformat specified.
This function will construct a DIB
instead of a DDB.

More information (still just on .NetCF bitmaps) here:

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

Update 2: some links relevant to .NET bitmaps in the full framework (summary at the bottom):

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

Summary: I think this question is difficult to answer because, basically, this (the actual location of the memory used by Bitmap) is an internal .NET implementation detail, mostly undocumented for a good reason. Since it appears that you can't really be sure where the bitmap's memory lives right now, and you definitely can't be sure where it will live in the future, I'd have to say MSDN probably wasn't kidding when they said:

Caution

Classes within the System.Drawing
namespace are not supported for use
within a Windows or ASP.NET service.
Attempting to use these classes from
within one of these application types
may produce unexpected problems, such
as diminished service performance and
run-time exceptions.

偏爱自由 2024-09-07 11:48:32

经过大量研究,我确定虽然不支持 System.Drawing 命名空间,但 它可能适用于很多人(可能不适合我们,因为我们进行了大量的图像处理)。

但是,支持的是 Windows 成像组件 ,但是它不是托管代码,尽管它们确实为 Win32 调用提供了一个薄的 .Net 包装器。 Bertrand Le Roy 的博客有一篇关于如何使用它的文章: 从 ASP.NET 调整图像大小的最快方法。而且它是(更多)受支持的。 WIC 似乎比 GDI+ 快得多。

Bertrand 还介绍了如何使用 WPF 操作图像,WPF 不受支持,但使用 WIC,似乎与直接 WIC 的性能相当,并且可能更容易编码。相关文章是: 使用 WPF/WIC 而不是 GDI+ 调整服务器中的图像大小

WIC 和 WPF 都需要完全信任,因此如果您在中等信任环境中工作,您将陷入困境与 GDI+。

After much research, I have determined that although the System.Drawing namespace is not supported, it will probably work for many people (probably not for us due to the high volume of images manipulation that we do).

However, what is supported is Windows Imaging Components, however it is not managed code though they do provide a thin .Net wrapper around the Win32 calls. Bertrand Le Roy's blog has an article on how to use it: The fastest way to resize images from ASP.NET. And it’s (more) supported-ish. WIC seems to be significantly faster than GDI+.

Bertrand also covers how to manipulate images uses WPF, which is not supported but uses WIC, seems to perform on par with direct WIC, and is probably easier to code. The article for that is: Resizing images from the server using WPF/WIC instead of GDI+

Both WIC and WPF require full trust so if you are working in a medium trust environment, you will be stuck with GDI+.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文