Утечки памяти AS3 BitmapData

Это простой тест на AS3 для выделения памяти BitmapData.

private function memoryTest(): void
{
  trace("BitmapData memory test. Create bmps..."); // First breakpoint
  var bmps:Array = new Array (1000);

  for (var i:int=0; i<1000; i++)
  {
    bmps[i] = new BitmapData(451, 451, true, 0);
    trace(i+". bmp created");
  }

  trace("All bmps created."); // Second breakpoint

  for (i=0; i<1000; i++)
  {
    bmps[i].dispose();
    bmps[i] = null;
  }
  bmps.splice(0, bmps.length);
  bmps = null;

  freeMemoryGC();

  trace("All bmps deleted.");
  trace("Test complete."); // Last breakpoint
}

private function freeMemoryGC(): void
{
  // the GC will perform a full mark/sweep on the second call.
  try
  {
    new LocalConnection().connect('foo');
    new LocalConnection().connect('foo');
  }
  catch (e:*)
  {
  }

  System.gc();
  System.gc();
}

В этом тесте есть 3 точки останова, которые прокомментированы в коде. Точки останова приостанавливают выполнение программы на некоторое время. Точки останова соответствуют горизонтальным линиям на этой диаграмме состояния памяти.

график использования памяти

У меня вопрос: почему не вся память была освобождена после вызовов dispose ()? Что не так в этом коде и как правильно очистить объекты BitmapData?

ОБНОВЛЕНИЕ 1: я не думаю, что проблема в сборщике мусора. dispose () работает вне сборщика мусора и должен освободить данные пикселей. Также в этом примере теоретически должно быть выделено 451 * 451 * 4 * 1000 байт. Но это тестовое приложение выделяет на 25% больше байтов в System.privateMemory, и эти 25% никогда не освобождаются сборщиком мусора и dispose ().

ОБНОВЛЕНИЕ 2: если я создам 13 изображений размером 4059x4059 пикселей вместо 100 изображений 451x451 пикселей, тогда объем памяти будет точно равен теоретическому размеру, а память будет освобождена правильно после вызова GC! Не знаю, почему так происходит.

ОБНОВЛЕНИЕ 3: вот мои результаты интервального теста, созданные Дэниелом Мессером в его ответе: график использования памяти при интервальном тесте


person Eugene    schedule 06.08.2012    source источник
comment
Выполните этот тест 100 раз, а затем проверьте. Я предлагаю Вам сделать интервал и запускать его на каждом кадре. Вызов GC не означает, что память вернется в то же состояние.   -  person turbosqel    schedule 06.08.2012
comment
Интересная идея про 100 раз и интервал.   -  person Eugene    schedule 07.08.2012
comment
Как вы звоните memoryTest()? Есть ли что-то помимо этой функции, выделяющее память?   -  person NoobsArePeople2    schedule 07.08.2012
comment
У вас есть результат инверсной проверки? Если память моментально растет - это значит, что у Вас утечка, если нет - все нормально. Не зацикливайтесь на утечке нескольких килобайт.   -  person turbosqel    schedule 07.08.2012
comment
Я думаю, что дополнительные 25% могут приходиться на создаваемые внутренние MIP-карты.   -  person Quasimondo    schedule 08.08.2012
comment
Я тоже думаю о внутренних мипмапах ... И нет возможности отключить мипмаппинг, да?   -  person Eugene    schedule 09.08.2012
comment
Даниэль Мессер создал в своем ответе интервальный тест. Показал, что память высвободилась правильно. Итак, турбодель был прав.   -  person Eugene    schedule 09.08.2012
comment
У вас утечка памяти. Вы удаляете прослушиватели событий для таймера?   -  person Daniel MesSer    schedule 09.08.2012
comment
И какой инструмент профилирования вы используете?   -  person Daniel MesSer    schedule 09.08.2012


Ответы (1)


Попробуй убрать фичу о локальном подключении в свободной памяти gc-function. Это решает проблему?

РЕДАКТИРОВАТЬ:

package nyx_gaming_group.as3_tests {
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.system.System;
import messer_entertainment.MesSerUtils;

/**
 * ...
 * @author Daniel Dahlkvist
 */
public class BitmapDataMemoryLeak extends Sprite {
    private var _bitmaps:Array;

    public function BitmapDataMemoryLeak() {
        run();
    }

    private function run():void {
        MesSerUtils.delayCall(createBitmaps, 150);
        MesSerUtils.delayCall(destroyBitmaps, 4500);
        MesSerUtils.delayCall(freeMemoryGC, 4700);
        MesSerUtils.delayCall(run, 8000);
    }

    private function createBitmaps():void {
        trace("BitmapData memory test. Create bmps..."); // First breakpoint
        _bitmaps = new Array(1000);

        for (var i:int = 0; i < 1000; i++) {
            _bitmaps[i] = new BitmapData(451, 451, true, 0);
        }

        trace("All bmps created."); // Second breakpoint            
    }

    private function destroyBitmaps():void {
        for (var i:int = 0; i < _bitmaps.length; i++) {
            _bitmaps[i].dispose();
            _bitmaps[i] = null;
        }
        _bitmaps = null;

        trace("All bmps deleted.");
        trace("Test complete."); // Last breakpoint
    }

    private function freeMemoryGC():void {
        System.gc();
    }
}
}
person Daniel MesSer    schedule 06.08.2012
comment
Я пытался. Но без взлома с локальным подключением память вообще не очищается. Автономный отладчик Flash player 11.1, win32. - person Eugene; 07.08.2012
comment
Я добавил пример кода, как я запускал этот код, мне кажется, что он работает нормально? Я добавил несколько временных интервалов [создает растровые изображения через 150 мс, затем уничтожает их через 4500 мс и заставляет GC запускаться через 4700 мс] - person Daniel MesSer; 07.08.2012
comment
вы можете найти изображение моего результата по следующему адресу: i48.tinypic.com/m7cc5k.png - person Daniel MesSer; 07.08.2012
comment
Вот мои результаты вашего теста. Очень интересно. - person Eugene; 09.08.2012
comment
Но вы можете ясно видеть, что это не растровые изображения, и ясно видеть, что у него нет утечки памяти. То, что вы показываете, - это какая-то дополнительная память, выделяемая при запуске программы. Но память не становится все больше и больше. Это могут быть такие вещи, как функции, классы и т. Д. - person Daniel MesSer; 09.08.2012