防止“内存不足”从较小的图像创建位图时的异常 [英] Prevent "out of memory" exceptions when creating bitmaps from smaller images

查看:88
本文介绍了防止“内存不足”从较小的图像创建位图时的异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

你好



我正在尝试创建一个tile编辑器应用程序,它将16x16大小的png图像连接到一个大的png文件中。我之前尝试开发其他应用程序并且未能解决内存泄漏问题或只是一般的GDI +错误时尝试了这个。



现在我知道这不是'这是我的电脑的问题,因为它有16GB RAM和8个处理器。所以这真的不应该是它的问题。



在处理位图和图形对象时,我读过很多关于处理和垃圾收集的帖子,但是我无论我走到哪里似乎都会得到相互矛盾的答案,有些人说......

- 您只需要处理对象或使用使用。 (我已经做过了)

- 其他人说尽管这很重要,但实际上他们在内存问题方面做的并不多。 (那我该怎么做才能解决这个问题?)



我的代码:



 公共  Sub  DisplayMap()

Dim ArtFilePrefix As String = My.Settings.usr_ArtDumpFolder& \& Tile _& IO.Path.GetFileNameWithoutExtension(_FilePath)& _

使用 MapBmp As Bitmap = 位图(_HeaderBlock.MapWidth * 16 ,_ HeaderBlock.MapHeight * 16
使用 MapGfx = Graphics.FromImage(MapBmp)

对于 TileHeight As UShort = 0 _HeaderBlock.MapHeight - 1
对于 TileWide As UShort = 0 _HeaderBlock.MapWidth - 1
使用 _MapBlock.MapCell(TileHeight * _HeaderBlock.MapWidth + TileWide)
MapGfx.DrawImage(
Bitmap.FromFile(ArtFilePrefix& _TextureRange( 0 )。StartAddress + _TextureBlock.OffsetTextureTable(.TextureIndex)& 。png),
矩形(TileWide * 16 ,TileHeight * 16 16 16 ),
矩形( 0 0 16 16 ),
GraphicsUnit.Pixel)
结束 使用
下一步
下一步

' \\保存文件并释放系统资源。
MapBmp.Save (My.Settings.usr_ArtDumpFolder& \& Map _& 。png,Drawing.Imaging.ImageFormat.Png)
结束 使用
结束 使用

结束 Sub





代码说明:



好的,所以这里有一些项目可能并不明显,他们做了什么,所以我给出了一些解释:这是什么:



 _HeaderBlock 



包含一般信息的结构,但是为了这个程序的目的,确定最终图像应该有多大。



 _MapBlock 



包含与正在绘制的特定16x16区域相关的信息的结构最终图片。



 _TextureBlo ck 



用于确定要获取的16x16 png文件并附加到最​​终图像。



< b>我尝试了什么:



将For语句中的Using语句与外部相对,以查看是否多次使用相同的对象导致它打破。



最后放入GC.Collect,看看我是否可以强迫它释放内存。



将磁贴保存到磁盘而不是将它们保存在内存中(我保留了它)

解决方案

引用:

其他人说尽管这很重要,但实际上它们在内存问题方面并没有做太多。

当不使用时使用

-statements CLR 最终来清理这些对象,但不能保证何时会发生这种情况。所以它可能导致不一致的行为。当使用使用 -statements时,在这方面肯定是安全的 * 但是可能还有其他问题。



然而,我的第一个观察是你实际上并没有在所有一次性物品上使用
-statements 你创建: Bitmap.FromFile(..) -call创建一个你不处理的位图。我建议改变它(在 -statement):

 使用 tileBmp 作为位图= Bitmap.FromFile(ArtFilePrefix& _TextureRange( 0  ).StartAddress + _TextureBlock.OffsetTextureTable(.TextureIndex)&  。png
MapGfx.DrawImage(tileBmp,
矩形(TileWide * 16 ,TileHeight * 16 16 16 ),
矩形( 0 0 ,< span class =code-digit> 16 , 16 ),
GraphicsUnit.Pixel)
结束 使用





除此之外:你编译你的项目吗? x86架构?然后你的PC的16MB RAM没有帮助 - x86进程的32位地址空间无法利用那么多,并且由于内存碎片,实际限制甚至可能低于理论限制。



我建议首先更改您的代码,如上所示。如果问题仍然存在,并且您当前正在为x86编译项目,请将其更改为x64。



* 编辑:使用使用 -statements你是安全的,因为CLR将使用 next 垃圾收集(不是立即,因为我上面的措辞可能暗示)。由于垃圾收集不能保证在您的应用程序尝试分配将导致OutOfMemory异常的内存量之前发生,因此仍然可能发生垃圾收集,但它不太可能反对不使用使用 -statements。

Hello

I am trying to create a tile editor application that joins 16x16 sized png images into one large png file. I have tried this before when trying to develop other applications and have failed to get around the issue of memory leakage or just general GDI+ errors.

Now I know this isn't an issue with my computer as it's got 16GB RAM and 8 processors. So really this shouldn't be much of an issue for it.

I have read many posts surrounding disposal and Garbage Collection when dealing with bitmaps and graphics objects, but I seem to get conflicting answers wherever I go, some saying...
- You just need to dispose of the objects or use a Using. (Which I have done)
- Others say that although this is important, they don't actually do much in terms of memory issues. (Then what do I do to resolve this?)

My code:

Public Sub DisplayMap()

    Dim ArtFilePrefix As String = My.Settings.usr_ArtDumpFolder & "\" & "Tile_" & IO.Path.GetFileNameWithoutExtension(_FilePath) & "_"

    Using MapBmp As Bitmap = New Bitmap(_HeaderBlock.MapWidth * 16, _HeaderBlock.MapHeight * 16)
        Using MapGfx = Graphics.FromImage(MapBmp)

            For TileHeight As UShort = 0 To _HeaderBlock.MapHeight - 1
                For TileWide As UShort = 0 To _HeaderBlock.MapWidth - 1
                    With _MapBlock.MapCell(TileHeight * _HeaderBlock.MapWidth + TileWide)
                        MapGfx.DrawImage(
                            Bitmap.FromFile(ArtFilePrefix & _TextureRange(0).StartAddress + _TextureBlock.OffsetTextureTable(.TextureIndex) & ".png"),
                            New Rectangle(TileWide * 16, TileHeight * 16, 16, 16),
                            New Rectangle(0, 0, 16, 16),
                            GraphicsUnit.Pixel)
                    End With
                Next
            Next

            '\\Save the file and release the system resources.
            MapBmp.Save(My.Settings.usr_ArtDumpFolder & "\" & "Map_" & ".png", Drawing.Imaging.ImageFormat.Png)
        End Using
    End Using

End Sub



Description of the code:

Ok, so there are a few items in here that may not be obvious as to what they do so I've given some explanation as to what these are:

_HeaderBlock


A structure that contains general information, but for the purposes of this procedure determines how big the final image should be.

_MapBlock


A structure that contains information related to the specific 16x16 area that is being drawn in the final image.

_TextureBlock


Used to determine what 16x16 png file to obtain and to append to the final image.

What I have tried:

Putting the Using statements within the For Loops opposed to the outside to see if using the same objects multiple times caused it to break.

Putting in a GC.Collect at the end to see if I could force it to free up memory.

Saving the tiles to disk opposed to keeping them in memory (I have kept this in)

解决方案

Quote:

Others say that although this is important, they don't actually do much in terms of memory issues.

When not using using-statements the CLR eventually comes around to cleaning up those objects but there's no guarantee on when this will happen. So it can lead to inconsistent behaviour. When using using-statements you're definitely on the safe side in this regard* but there can be other issues.

However, my first observation is that you don't actually use using-statements on all disposable objects which you create: The Bitmap.FromFile(..)-call creates a bitmap that you don't dispose of. I suggest changing it like this (within the With-statement):

Using tileBmp As Bitmap = Bitmap.FromFile(ArtFilePrefix & _TextureRange(0).StartAddress + _TextureBlock.OffsetTextureTable(.TextureIndex) & ".png")
    MapGfx.DrawImage(tileBmp,
                     New Rectangle(TileWide * 16, TileHeight * 16, 16, 16),
                     New Rectangle(0, 0, 16, 16),
                     GraphicsUnit.Pixel)
End Using



Other than that: Do you compile your project for x86 architecture? Then the 16MB RAM of your PC don't help - the 32bit address space of a x86 process can't utilize that much and because of memory fragmentation the practical limit can be even lower than the theoretical one.

I'd suggest to first change your code as shown above. If the problem persists and you currently compile your project for x86, change it to x64.

* Edit: With using-statements you're on the safe side as in that the CLR will clean up those objects with the next garbage collection (not instantly, as my above wording might imply). Since garbage collections are not guaranteed to happen before your application tries to allocate an amount of memory that will lead to an OutOfMemory-exception it's still possible that one occurs but it's far less likely opposed to not using using-statements.


这篇关于防止“内存不足”从较小的图像创建位图时的异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆