Моя программа шипы от 100 000 до 1 000 000 К К мем мем в течение нескольких минут в моей программе в VB.net


Я создал программу, которая использует систему.Графики для визуализации простой (малый) 2Д сцены на экране. Проблема, по некоторым причинам, она начинает быстро накапливаться в памяти. На самом деле, это идет только от 100,000 к mem в десять раз и затем завершает работу. Как и ожидалось, частота кадров программы резко падает, а (100+ до 1fps).

Я думаю, что виновный в цикле рендеринга. Проблема в том, как сложно, как я Поиск, кроме пары кусочков грязный код, я не могу найти хоть какое-то отношение к проблеме.

Оно не может быть внутри этого фрагмента кода, если нет - это нормально. Я буду продолжать мой лично искать через мое приложение.

Вот мой двигатель.глаг источник:

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.

В принципе, переменные находятся на вершине, у меня тоже есть мой суб рендер() в нижней части. Если вам нужен любой другой код, я позабочусь о том, чтобы разместить его. Просто так сказать в комментариях.

Помните: я не 100% уверен, что проблема заключается в этом одном классе (или в этом классе на все). Если вы не можете найти причину, так и будет. Что-нибудь, чтобы ускорить его (если возможно, мой грязный программирования замедлил его, что плохо) также будут оценены.

Редактирование 1

Пожалуйста, взгляните на следующий скриншот мне муравьев, используя профилировщик памяти:

enter image description here

У меня есть многомерный массив, который содержит экземпляры класса 'GridElement'. Массив-это 3D. Я использую его в слой и сделать элементы из конкретного места для отображения. Согласно этого, хотя, он говорит, что это принимает как 94% памяти моего приложения, и по большей части, он наполнен пустые слоты. Наибольшее количество элементов я вложил в это, как 20-30 (это только часть того, что он должен уметь обрабатывать).

Так что в принципе, как это пустой 3D массива занимают так много места, когда есть только несколько элементов в нем?



414
3
задан 27 сентября 2011 в 11:09 Источник Поделиться
Комментарии
1 ответ

Во-первых; используйте хороший профайлер памяти. Если вы можете рассуждать о том, почему нечто подобное происходит быстро, то отлично. В противном случае вы тратите время, когда есть много отличных инструментов там, которые могут сделать вашу жизнь намного проще. Я лично использую РГ-а, профайлер для .Net-приложений (я никак не связан с ними, я просто думаю, что это действительно хорошая и в ней есть 14-дневная бесплатная пробная полнофункциональная).

Сейчас, на ваш код...

Вы создаете графические объекты без удаления их в одном месте. Она должна быть:

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 является плохой идеей, так как он будет бросать (обработано) исключение, если значение не найдено. Вы действительно не хотите бросать исключения в этой области кода. Конструкция его такая, что можно предположить, что значение существует.

Вы также создает большое растровое изображениеС. Если это называется в непрерывном цикле, то у вас может не быть достаточно времени для GC, чтобы прийти в себя за вами убирать. Кроме того, в память вероятно, выделенных на Лох (куче больших объектов), так что вы можете иметь большое фрагментации происходит. Почему бы не использовать один растровый и покончить с этим? Вам не надо создавать новый каждый раз, если ширина и высота постоянны, что это действительно необходимо для игры. Просто нарисовать за тот же буфер кадра, в каждый вызов отрисовки.

Снова, хотя, сходи в приличный профайлер. Он расскажет вам где ваша память выделяется и он будет также предупредить вас о Лох-фрагментации, а также интерфейс IDisposable объекты, что вы не вызов метода Dispose() на.

Редактировать: Вы читаете неправильно ваши результаты профилирования. Он говорит вам, что 784MB (в подавляющем большинстве памяти, выделенной для процесса) является неуправляемым, т. е., вероятно, Bitamps. Искать IDisposables, что вы не выбрасывайте. Вы пытались использовать один буфер экрана, вместо того чтобы создавать каждый кадр, как я предложил?

У вас также есть ~800МБ, выделенных для выполнения, которая не используется. Вам нужно продолжать с профайлером и анализировать результаты. Это только на первой странице, у них есть уроки, которые будут вести вас через все остальное.

5
ответ дан 27 сентября 2011 в 11:09 Источник Поделиться