AS3: “хитрая” утечка памяти при работе с Vector


Многим часто приходится писать много кода. Сначала проектировать, потом писать, потом оптимизировать. И когда программируешь на AS3, то тебе известна (обычно) куча мелких нюансов, как лучше писать код, чтобы потом было меньше проблем с памятью и её утечками. Но за всем не уследишь и иногда в самых банальных блоках кода могут скрываться суровые утечки памяти.

Недавно я обнаружил утечку там, где совсем не ожидал, что меня сильно удивило после стольких лет работы с AS3.

Иногда стоит задача заполнить Vector, чтобы потом передать его дальше на какой-нибудь модный метод, который дальше «сделает хорошо». Иногда приходится это делать очень часто или даже каждый кадр.

Несколько лет без всякого сомнения я делал это примерно так:


Ну вроде ничего особенного – занулил длинну вектора, заполнил по новой. Без задней мысли такими блоками забивался не один большой проект. Но однажды передо мной стала задача найти и устранить утечки памяти в расширении для Starling для 2D-теней и освещения. Каждая тень каждый кадр пересчитывала координаты своих вершин, далее составлялся большой вектор из них и обрабатывался далее. Так вот при 50 объектах их тени «текли» со скоростью в 300-500кб в секунду, что сильно раздражало. После долгих мучений выяснилось, что «виноват» способ составления вектора, который я привел выше – при занулении длинны вектора все индексы при push создаются по новой и отъедают память. А так как этот процесс повторяется каждый кадр, память успевает быстро накапливаться.

После некоторых скитаний по интернетам решение изначально подсказал камрад Vadim BELLinSKY из Одессы! Так же благодарю Макара Осокина и остальной профильный Skype-чатик. Выглядит решение так:



То есть мы обрезаем длину вектора до которой нам надо, потом обновляем старые индексы.

Тут мы имеем несколько вариантов:

  1. Наш вектор пойдет на какой-то сторонний метод, который возьмет этот вектор, будет у него вычислять длину и дальше перебирать – тогда да, нужна эта обрезка по длине в конце составления вектора. Тогда в следующий раз, если элементов в векторе будет больше чем индексов, новые индексы будут созданы без проблем.
  2. Если весь код свой, то можно ввести отдельную переменную и считать количество элементов и далее не брать у вектора свойство length, а использовать эту отдельную переменную – это поможет сэкономить на выделение памяти для новых индексов.
  3. Сразу после создания вектора назначить ему длину, чтобы сразу была выделена память.

    Так что теперь нужна новая мелкая привычка – сделать за push…
    Вероятно с Array та же история :)

    Похожие записи:


7 Responses to AS3: “хитрая” утечка памяти при работе с Vector

  1. k0t0vich Reply

    я так и не понял зачем
    Math.random()
    просто i или 0 – никак?
    пс. смени тему – очень сложно писать серым на сером.


  2. industred Reply

     

    А с Push что не так?


    • Валерий Бохан Reply

      Push новый индекс создает, выделяет память под него. То есть выгоднее перезаписывать старые индексы, чем занулять массив и через push его по новой заполнять. Получается некий object pooling для индексов массива/вектора.


  3. Dukobpa3 Reply

    Только мне оба приведенных метода издалека костыль напоминают?
    Я всегда вот так делаю:

    while (v.length > needed) v.pop();
    while (v.length < needed) v.push(new Some());

    а дальше просто установка значения по индексу.


  4. smertik Reply

    У меня вопросик маленький:

    А фиксация длинны обязательна или опциональна ?

    Т.е. я могу например занулить длину и потом записывать индексы вторым способом ?

    Или же если так не пойдет то просто выставить новую максимальную длину и не трогать фиксы ?

    Это не принципиально просто хочется сэкономить на строках кода =]


    • Валерий Бохан Reply

      Сложно сказать, надо замерять как быстрее. На сколько я помню – фиксированная длина быстрее работает – быстрее доступ к данным по индексам, поэтому лучше установить её заранее, потом добавлять элементы. Я бы замерил разные варианты и взял то, что быстрее работает.

Leave a Reply

Your email address will not be published. Please enter your name, email and a comment.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">