我已经创建了一个程序,它使用System.Graphics向屏幕呈现一个简单的(小的) 2D场景。问题是,由于某种原因,它开始迅速积累记忆。事实上,它从100,000千兆升到了10倍,然后崩溃了。正如预期的那样,程序的帧率也急剧下降(100+到1fps)。
我相信罪魁祸首在我的渲染循环中。问题是,尽管我搜索的很辛苦,除了一些杂乱无章的代码之外,我找不到任何与问题相关的东西。
它可能不在这个代码片段中--如果不是,没关系。我将继续我的个人搜索通过我的申请。
以下是我的Engine.vb源代码:
Public Class Engine
Public debugEnabled As Boolean = False
Private _currentMap
Public Property currentMap As Map
Get
Return _currentMap
End Get
Set(ByVal value As Map)
_currentMap = value
luaEngine.Close()
cTime.Reset()
sprites.Clear()
cTime.Start()
luaEngine = New Lua
End Set
End Property
Public currentData As MemoryGrid
Public currentInstance As MemoryGrid
Public fForm As Control
Public cTime As New Stopwatch
Public buffer As Bitmap
Friend Shared luaEngine As New Lua
Public sprites As New Dictionary(Of String, Bitmap)
#Region "EVENTS"
Public Event event_keydown(ByVal key As String)
Public Event event_keyup(ByVal key As String)
#End Region
Public Sub Render()
Dim fpsTimer As New Stopwatch
fpsTimer.Start()
If fForm IsNot Nothing Then
If buffer IsNot Nothing Then
Dim e As Graphics = fForm.CreateGraphics()
e.InterpolationMode = Drawing2D.InterpolationMode.NearestNeighbor
e.DrawImage(buffer, New Rectangle(0, 0, fForm.Width, fForm.Height))
buffer.Dispose()
End If
buffer = New Bitmap(fForm.Width, fForm.Height)
Using gfx As Graphics = Graphics.FromImage(buffer)
gfx.FillRectangle(Brushes.Black, 0, 0, fForm.Width, fForm.Height)
If currentMap IsNot Nothing Then
For z As Integer = 0 To Grid.LAYERLIMIT
For x As Integer = currentMap.DisplayXOffset To currentMap.DisplayXOffset + Math.Ceiling(fForm.Width / 8)
For y As Integer = currentMap.DisplayYOffset To currentMap.DisplayYOffset + Math.Ceiling(fForm.Height / 8)
Dim terrObj As GridElement = currentMap.Level.getCell(z, x, y)
If terrObj IsNot Nothing Then
Dim _position As Point
Dim _size As Size
terrObj.tileImage(Me, _position, _size)
Dim cSprites As Bitmap = Nothing : sprites.TryGetValue(terrObj.SpriteSheet & ".png", cSprites)
gfx.DrawImage(cSprites, (x - currentMap.DisplayXOffset) * 8 + terrObj.XOffset, (y - currentMap.DisplayYOffset) * 8 + terrObj.YOffset, New RectangleF(_position.X, _position.Y, _size.Width, _size.Height), Drawing.GraphicsUnit.Pixel)
End If
Next
Next
Next
End If
gfx.DrawString("FPS: " & Math.Round(1000 / fpsTimer.ElapsedMilliseconds), New Font("Arial", 7), Brushes.Red, New PointF(5, 5))
fpsTimer.Stop()
End Using
End If
End Sub'...
在此之后还有几个过程,但是,它们与我的Lua实现有关。这个问题在我实施Lua之前就已经存在了。
基本上,变量在顶部,我的Sub Render()也在底部。如果您需要其他代码,我会确保将其发布。只需在评论中这样说。
记住:我不能百分之百地确定这个问题是在这个类中(或者在这个类中)。如果你找不到理由,那就去吧。任何能加快速度的东西(如果我的杂乱无章的编程让它慢下来了那么糟糕的话)也会受到欢迎的。
请看下面使用蚂蚁记忆分析器的我的截图:

我有一个多维数组,它包含一个名为“GridElement”的类的实例。数组是三维的。我使用它来分层并从特定的位置获取要显示的元素。然而,根据这一点,它占用了我应用程序内存的大约94%,而且在大多数情况下,它都充满了空槽。我所投入的元素数量最多的是20-30 (这只是它需要处理的部分)。
基本上,当这个空的3D数组中只有几个元素时,它怎么会占用这么多空间呢?
发布于 2011-09-27 23:54:33
首先,使用一个好的内存分析器。如果你能解释为什么这样的事情会很快发生,那就没问题了。否则,当有很多很棒的工具可以让你的生活变得更容易的时候,你就是在浪费时间。我个人使用雷德盖特侧写器为.NET应用程序(我与他们没有关系,我只是认为它真的很好,它有一个14天的免费试用,功能齐全)。
现在,进入你的密码..。
您正在创建Graphics对象,而不是在一个区域内对它们进行处理。它应该是:
Using e As Graphics = fForm.CreateGraphics()
e.InterpolationMode = Drawing2D.InterpolationMode.NearestNeighbor
e.DrawImage(buffer, New Rectangle(0, 0, fForm.Width, fForm.Height))
buffer.Dispose()
End Using接下来,您有一些代码在紧密的呈现循环中确实不是最优的。例如,使用TryGetValue是个坏主意,因为如果找不到值,它就会抛出一个(已处理的)异常。您真的不想在代码中抛出异常。设计它时,您可以假设值存在。
你也创造了很多Bitmaps,如果这是一个紧密的循环,那么你可能没有足够的时间让GC在你之后进行清理。此外,内存很可能是在LOH (大型对象堆)上分配的,因此可能会有很多碎片。为什么不使用一个Bitmap并完成它呢?如果宽度和高度是恒定的,则不需要每次创建一个新的,这对于一个游戏来说是应该的。只需在每次对Render的调用中绘制相同的帧缓冲区即可。
再一次,去使用一个像样的分析器。它将告诉您在何处分配内存,还将提醒您注意LOH碎片,以及您没有调用IDisposable的Dispose()对象。
编辑:您正在错误地读取分析结果。它告诉您784 to (分配给您的进程的绝大部分内存)是非托管的,即可能是Bitamps。查找您没有处理的IDisposables。您是否尝试过使用单个屏幕缓冲区,而不是像我建议的那样创建每一个帧?
您还将~800 to分配给未使用的运行时。您需要继续使用分析器并分析结果。这只是第一页,他们有教程,将引导您通过其余的。
https://codereview.stackexchange.com/questions/5027
复制相似问题