Почему Sytem.totalMemory продолжает увеличиваться?

Подумайте также об инструменте gitk, снабженном git и очень полезным, чтобы увидеть изменения

7
задан Spooky 19 June 2015 в 21:14
поделиться

5 ответов

Я думаю, вы ошиблись в паре вещей.

Во-первых, ваши трассировки отображают totalMemory с усечением последних трех цифр (поскольку вы не делаете этого в коде, я полагаю это из-за ширины TextField). Он увеличивается следующим образом: 3076, 3092, 3096 и т.д. Это (примерно) килобайты, а не байты. Тогда вы комментируете: «totalMemory через 2 часа: 3887104. Боже мой». Теперь, если под 3 887 104 вы имеете в виду 3 887 104 КБ, это будет около 3,8 ГБ. Я сомневаюсь, что это так, поэтому предположим, что вы имеете в виду 3 887 104 байта. Это примерно 3800 Кбайт или 3,8 Мбайт. На самом деле не так уж много памяти и, что более важно, не так уж далеко от ваших первоначальных 3076 Кб.

Я думаю, что это на самом деле вводит в заблуждение другого автора, думая, что игрок увеличивает использование памяти на 4 байта, когда оно фактически увеличивается на 4096 байтов, или 4 Кб.

Второй, хотя код очень прост, он потребляет память. Во-первых, каждый раз, когда отправляется событие ENTER_FRAME, создается объект Event, который, в свою очередь, содержит ссылки на другие объекты, строки и т. Д. Это требует памяти. Затем вы неявно конвертируете число в строку (печатая totalMemory). Это также требует памяти, независимо от того, выполняете ли вы явное преобразование или нет (то же самое применимо, если вы делаете трассировку вместо использования текстового поля). Вдобавок ко всему, наверняка происходят и другие вещи, которые не очевидны с «точки зрения ActionScript».

Я думаю, что отчасти проблема заключается в том, что вы просто отслеживаете текущий totalMemory. Глядя на него, кажется, что он все время медленно, но неуклонно растет. И это правда, но вы, вероятно, упускаете из виду то, что в более медленном темпе сборщик мусора срабатывает и высвобождает большую часть накопленной памяти.

Это станет более очевидным, если вы измените код, чтобы вычислить несколько вещей.

package{
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.system.System;
    import flash.text.TextField;
    import flash.utils.getTimer;
    import flash.text.TextField;
    import flash.text.TextFormat;

    public class Test extends Sprite {

        private var peak:int            = 0;
        private var prev:int            = 0;
        private var cur:int             = 0;
        private var diff:int            = 0;
        private var decreaseCount:int   = 0;
        private var increaseCount:int   = 0;
        private var accumIncrease:int   = 0;
        private var accumDecrease:int   = 0;
        private var maxIncrease:int     = 0;
        private var maxDecrease:int     = 0;
        private var initTime:Number     = 0;
        private var elapsed:Number      = 0;

        private var time:TextField;
        private var info:TextField;

        public function Test() {
            initTime = getTimer();
            var tf:TextFormat = new TextFormat("Courier New",12);
            time = new TextField();
            time.defaultTextFormat = tf;
            time.width  = 250;
            addChild(time);
            info = new TextField();
            info.defaultTextFormat = tf;
            info.y = 15;
            info.width  = 250;
            info.height = 250;
            addChild(info);
            addEventListener(Event.ENTER_FRAME,Loop);
        }

        public function Loop(e:Event) {
            cur = System.totalMemory >> 12;

            elapsed     = (getTimer() - initTime) / 1000; 
            time.text   = "time running:        " + elapsed;

            if(cur == prev) {
                return;
            }

            if(cur > peak) {
                peak = cur;
            }

            if(cur > prev && prev > 0) {
                diff = cur - prev;
                if(diff > maxIncrease) {
                    maxIncrease = diff;
                }
                accumIncrease += diff;
                increaseCount++;
            } else if(cur < prev) {
                diff = prev - cur;
                if(diff > maxDecrease) {
                    maxDecrease = diff;
                }
                accumDecrease += diff;
                diff = -diff;
                decreaseCount++;
            }

            info.text   =   "current:           " + cur + "\n"
                        +   "previous:          " + prev + "\n"
                        +   "diff:              " + diff + "\n"
                        +   "peak:              " + peak + "\n"
                        +   "increaseCount:     " + increaseCount + "\n"
                        +   "decreaseCount:     " + decreaseCount + "\n"
                        +   "accumIncrease:     " + accumIncrease + "\n"
                        +   "accumDecrease:     " + accumDecrease + "\n"
                        +   "maxIncrease:       " + maxIncrease + "\n"
                        +   "maxDecrease:       " + maxDecrease;

            prev    = cur;

        }
    }
}

Я использую куски по 4096 байт в качестве единицы (Это почему я делаю System.totalMemory >> 12. Просто причудливый способ сказать System.totalMemory / 4096). Я думаю, что это более управляемо, и в любом случае totalMemory всегда возвращает кратные 4096 байтов или 4 КБ. Вы можете узнать больше о GC Flash здесь: https://developer.mozilla.org/en/MMgc . Эта часть плеера имеет открытый исходный код, и вы даже можете прочитать источники, если захотите.

Краткое объяснение того, что отслеживает код:

  • время выполнения: Прошло секунд с момента запуска swf running
  • current: Объем памяти, возвращаемый System.totalMemory, фрагментами по 4 КБ
  • предыдущий: Предыдущее значение totalMemory
  • diff: Разница между текущим и предыдущим. Может быть отрицательным. Это показывает, увеличилось или уменьшилось использование памяти по сравнению с предыдущим значением.
  • пик: Самостоятельное объяснение. Это не очень важно.
  • IncreaseCount: Сколько раз текущий был больше предыдущего. По сути, он сообщает вам, во сколько раз было увеличено значение totalMemory, по крайней мере, на 1 кусок.
  • reduceCount: Сколько раз предыдущее значение было больше текущего. Это покажет вам, сколько раз память была освобождена.
  • accumIncrease: Накопленное значение положительных разностей. Сообщит вам, сколько блоков было выделено.
  • accumDecrease: Накопленное значение отрицательных разностей. Сообщит вам, сколько фрагментов было освобождено.
  • maxIncrease: Максимальное количество фрагментов, выделенных при выполнении двух циклов.
  • maxDecrease: Максимальное количество фрагментов, освобождаемых при выполнении двух циклов.

Теперь давайте посмотрим на некоторые «снимки», сделанные с помощью этого кода.

Это ранний снимок, сделанный во время выполнения файла swf. работает 3 секунды. Просто обратите внимание, что ток составляет 760.

  • время работы: 3 секунды
  • ток: 760
  • предыдущий: 759
  • разн .: 1
  • пик: 760
  • увеличитьCount: 3
  • reduceCount: 0
  • накопление: 6
  • накопление: 0
  • макс. Увеличение: 3
  • макс. Уменьшение: 0

Примерно через 10 минут:

  • время работы: 574 сек
  • текущее: 763
  • предыдущая: 762
  • curDiff: 1
  • пик: 834
  • увеличитьCount: 127
  • reduceCount: очень близко к тому, что было в 3 секунды: 763 против 760. Это означает, что прямо сейчас общая память 3.052 Мб; В 3 сек, это было 3040 Мб.
  • Количество увеличения велико, а количество уменьшений низкое. Это значит игрок выделил память много раз, но выпустил очень экономно.
  • maxIncrease низкий, maxDecrease в приоритете. Добавьте это к 2), и у вас есть интересный узор: игрок выделяет небольшое количество блоков часто. Он выпускает их в гораздо более медленный темп; когда это произойдет, однако, это освобождает большое количество фрагментов.
  • accumIncrease и accumDecrease являются тоже очень близко.
  • Теперь позвольте swf поработать еще немного. После 50 минут работы снимок выглядит следующим образом:

    • время выполнения: 2989 секунд
    • текущее: 931
    • предыдущее: 930
    • разн .: 1
    • пиковое: 931
    • увеличение: 690
    • ReduceCount: 8
    • Накопление: 699
    • НакоплениеDecrease: 522
    • maxIncrease: 3
    • maxDecrease: 163

    Здесь вы можете подумать, что произошла утечка. Обратите внимание на то, что текущая память - 931, по сравнению с начальными 760.

    Но посмотрите, что происходит через 3124 секунды, ~ 52 минуты:

    • время работы: 3142 секунды
    • текущее: 767
    • предыдущее: 768
    • ] diff: -1
    • пиковое: 962
    • увеличение: 720
    • уменьшение: 10
    • накопление: 730
    • накопление: 717
    • макс. увеличение: 3
    • макс. уменьшение: 194

    До того, как заработал GC, пик вырос до 962. Но после этого ток упал до 767, опять же, очень близко к начальному 760.

    Итак, чтобы подвести итог, тот факт, что использование памяти растет, не обязательно означает утечку. Вам просто нужно иметь дело с тем фактом, что проигрыватель собирает мусор, и этот процесс не детерминирован. В конце концов, в какой-то момент память будет восстановлена ​​(если, конечно, в вашем коде не будет утечки). Вы не можете определить, когда это произойдет. Это произойдет, когда игрок сочтет это необходимым. И вообще игроку виднее.

    Тем не менее, я считаю важным обращать внимание на возможные утечки в вашем коде. Но простая трассировка System.totalMemory не поможет вам определить это. По возможности используйте такой инструмент, как профилировщик памяти Flex Builder, который не идеален, но дает гораздо больше полезной информации.

25
ответ дан 6 December 2019 в 06:50
поделиться

Вы можете проверить, какую версию Flash-плеера вы используете. Если у вас установлена ​​IDE, велика вероятность, что вы работаете в отладочной версии плеера, которая, как правило, не так часто (если вообще) освобождает память по сравнению с обычным плеером.

Если вы работаете в проигрывателе отладки вы можете принудительно выполнить очистку gc - System.gc ();

1
ответ дан 6 December 2019 в 06:50
поделиться

Насколько я могу судить, в каждом цикле вызов System.totalMemory возвращает uint, представляющий объем памяти в байтах, который используется Flash. Uint, возвращаемый вызовом System.totalMemory, сохраняется в памяти (то есть в вашей оперативной памяти, а не в текстовом поле, которое вы пометили как «память»). Затем ссылка memory.text обновляется, чтобы указать на пространство в памяти, занимаемое uint. Старый uint все еще находится в памяти, но на него нет ссылки. Uints - это 32 бита (4 байта) данных, поэтому каждый раз вы видите, что объем памяти увеличивается на 4 байта. Как только сборщик мусора запустится, пространство в памяти, занятое разыменованными uint'ами, должно освободиться, и вы должны увидеть падение памяти.

Однако, когда я запускаю ваш пример кода, я не получаю ничего подобного. Он поднимается и опускается, это не так

0
ответ дан 6 December 2019 в 06:50
поделиться
​​

По мере изменения текста в текстовом поле Flash придется загружать в память различные символы для их отображения. Это могло бы объяснить получаемое вами увеличение на несколько сотен байтов.

Оставшись в покое, насколько больше становится след?

ОБНОВЛЕНИЕ: Подумав об этом, я думаю, что это связано с временной растровой графикой, которая создается для Flash для визуализации текста ... хотя вы бы не стали Не ожидал, что с трассировкой ... хотя трассировка тоже должна делать некоторые внутренние вещи ...

Вы думали запустить ее в FlexBuilder? У этого есть инструмент профилирования, который может сказать вам, куда уходит ваша память.

0
ответ дан 6 December 2019 в 06:50
поделиться

Возможно, это очевидно, но помните, что System.totalMemory дает вам объем памяти, используемый Flash Player (статический). Если у вас открыто другое Flash-приложение, это может объяснить, почему объем вашей памяти увеличивается.

0
ответ дан 6 December 2019 в 06:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: