Я думаю, вы ошиблись.
Во-первых, в ваших трассах отображается TotalMemory, усекающая последние 3 цифры (поскольку вы не делаете этого в коде, я предполагаю, что это из-за ширины TextField). Он растет примерно так: 3076, 3092, 3096 и т. Д. Это (примерно) килобайты, а не байты. Затем вы комментируете: «Всего памяти через 2 часа: 3887104. Боже мой». Теперь, если под 3,887,104 вы подразумеваете 3,887,104 Кб, это будет около 3,8 Гб. Я сомневаюсь, что это так, поэтому давайте предположим, что вы имеете в виду 3887 104 байтов. Это около 3800 Кб или 3,8 Мб. Не так много памяти, на самом деле, и, что более важно, не так далеко от ваших начальных 3076 Кб.
Я думаю, что это на самом деле вводит в заблуждение другого автора, считая, что проигрыватель увеличивает потребление памяти на 4 байта, тогда как он фактически увеличивается на 4 096 байтов или 4 Кб.
Во-вторых, хотя код очень прост, он потребляет память. Для начала, каждый раз, когда отправляется событие ENTER_FRAME, создается объект Event, который, в свою очередь, содержит ссылки на другие объекты, строки и т. Д. Это требует памяти. Затем вы неявно преобразуете число в строку (печатая totalMemory). Это также занимает память, независимо от того, выполняете ли вы явное преобразование или нет (то же самое применимо, если вы делаете трассировку вместо использования текстового поля). Вдобавок ко всему, наверняка происходят другие вещи, которые не очевидны с «точки зрения ActionScript».
Теперь я думаю, что отчасти проблема в том, что вы просто отслеживаете текущую общую память. Глядя на это, кажется, что он растет, медленно, но неуклонно, все время. И это правда, но вам, вероятно, не хватает того, что медленнее GC запускает и освобождает большую часть накопленной памяти.
Это становится более очевидным, если вы измените код для вычисления нескольких вещей.
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
- текущий: Объем памяти, возвращаемый System.totalMemory, кусками по 4 Кбайт
- предыдущее: предыдущее значение totalMemory
- diff: Разница между текущим и предыдущим. Может быть отрицательным. Это показывает, увеличилось или уменьшилось использование памяти относительно предыдущего значения.
- пик: Самоочевидно. Это не очень важно.
- увеличенияCount: Количество раз, когда ток был больше, чем предыдущий. По сути, он сообщает, во сколько раз был увеличен общий объем памяти, по крайней мере, на 1 кусок.
- lowerCount: Количество раз, когда предыдущий был больше текущего. Это скажет вам, сколько раз была освобождена память.
- аккумуляторIncrease: Накопленное значение положительных различий. Даст вам знать, сколько кусков было выделено.
- АКБДирект: Накопленное значение отрицательных различий. Даст вам знать, сколько кусков было выпущено.
- maxIncrease: Максимальное количество чанков, выделенных в двух выполнениях цикла.
- maxDecrease: Максимальное количество чанков, выпущенных за два выполнения цикла.
Теперь давайте посмотрим на некоторые «снимки», сделанные с использованием этого кода.
Это ранний снимок, сделанный, когда SWF работал в течение 3 секунд. Просто обратите внимание, что текущий читает 760.
- время работы: 3 с
- ток: 760
- предыдущий: 759
- diff: 1
- пик: 760
- увеличениеCount: 3
- уменьшениеCount: 0
- увеличение на 6: 1085 *
- нужное уменьшение: 0
- maxIncrease: 3
- maxDecrease: 0
Примерно через 10 минут:
- время работы: 574 с
- ток: 763
- предыдущий: 762
- curDiff: 1
- пик: 834
- увеличениеCount: 127
- уменьшениеCount: 3
- увеличение: 132
- общее снижение: 123
- maxIncrease: 3
- maxDecrease: 72
Несколько замечаний:
- Примерно через 10 минут ток
очень близко к тому, что было в 3 сек:
763 против 760. Это значит прямо сейчас,
общая память составляет 3,052 Мб; В 3
с, это было 3040 Мб.
- Количество увеличений велико, и
Количество уменьшений мало. Это означает
игрок выделил память
много раз, но выпустили очень
экономно.
- maxIncrease низкое и maxDecrease
в приоритете. Добавьте это к 2), и у вас есть
интересная картина: игрок
выделяет небольшое количество кусков
часто. Это выпускает их в
гораздо более медленный темп; когда это делает, однако, это
выпускает большое количество фрагментов.
- Накопления и увеличения накопления
тоже очень близко.
Теперь позвольте SWF запустить еще немного времени. После 50 минут работы снимок выглядит так:
- время: 2989 с
- ток: 931
- предыдущий: 930
- diff: 1
- пик: 931
- увеличениеCount: 690
- уменьшениеCount: 8
- увеличение: 699
- общее снижение: 522
- maxIncrease: 3
- maxDecrease: 163
В этот момент вы можете подумать, что есть утечка. Обратите внимание, что текущая память 931, по сравнению с начальной 760.
Но посмотрите, что происходит за 3124 секунды, ~ 52 минуты:
- время работы: 3142 с
- ток: 767
- предыдущий: 768
- diff: -1
- пик: 962
- увеличениеCount: 720
- уменьшениеCount: 10
- увеличение: 730
- общее снижение: 717
- maxIncrease: 3
- maxDecrease: 194
До того, как GC вступил в силу, пик вырос до 962. Но после этого ток снизился до 767, опять же, очень близко к начальным 760.
Итак, если говорить об этом, то факт увеличения использования памяти не обязательно означает, что произошла утечка. Вам просто нужно иметь дело с тем фактом, что игрок собирает мусор, и этот процесс не является детерминированным. Память в конечном итоге будет восстановлена в какой-то момент (если, конечно, у вас нет утечки в вашем коде). Вы не можете определить, когда это произойдет. Это произойдет, когда игрок определит, что это необходимо. И вообще, игрок знает лучше.
Тем не менее, я думаю, что важно обратить внимание на возможные утечки в вашем коде. Но просто отслеживание System.totalMemory не поможет вам определить это. Если вы можете, используйте инструмент, такой как профилировщик памяти Flex Builder, который не идеален, но дает вам гораздо больше полезной информации. И будьте осторожны при добавлении слушателей на сцену и при использовании таймеров, самые большие причины утечки памяти во флеш-плеере.