Вызов System.gc() в мобильном телефоне

Мне нужно поддерживать приложение J2ME. В приложении много System.gc(). Перед вызовом System.gc() все атрибуты устанавливаются равными нулю. Имеет ли смысл устанавливать для атрибутов значение null? Имеет ли смысл звонить System.gc()? Разве jvm не должен вызывать сборщик мусора, когда это необходимо?


person Daniel Moura    schedule 22.05.2009    source источник


Ответы (5)


Причина всех обнулений атрибутов и вызовов System.gc() определенно является частью борьбы с фрагментацией устройств. Достаточно просто сказать, что вы никогда не должны обнулять значение самостоятельно, что вы должны позволить ему просто выйти за рамки, и на самом деле это подходящий способ для разработки ПК. Тем не менее, мобильное пространство — это совершенно другое животное, и было бы наивно говорить, что вы можете управлять памятью так же на ограниченном мобильном устройстве, как и на ПК, в распоряжении которого есть гиги и гигабайты оперативной памяти.

Даже сейчас смартфоны высокого класса имеют около 32-64 МБ динамической памяти, доступной для приложения J2ME. Размер многих устройств по-прежнему составляет около 1–4 МБ, и часто для соответствия спецификациям оператора вам необходимо настроить таргетинг на еще меньшие размеры кучи. Razr имеет только 800 КБ кучи и по-прежнему требуется для поддержки большинства операторов из-за того, что многие их абоненты все еще используют это устройство.

Фрагментация памяти происходит из-за того, что даже если блок памяти больше не используется, если он был аннулирован, он все еще недоступен до тех пор, пока не будет удален сборщиком мусора. Большинство мобильных ВМ выполняют сбор мусора только тогда, когда требуется память. Поэтому, когда он, наконец, запустит сборщик мусора, куча может быть фрагментирована на крошечные блоки памяти. Когда необходимо выделить больший блок памяти, он не сможет выделить меньший блок. Если у вас достаточно этих меньших блоков, загрязняющих кучу, не предоставляющих блок, достаточно большой для более крупного объекта, в конечном итоге вы получите исключение OutOfMemory, даже если может показаться, что у вас есть тонны доступной памяти.

Например, представьте, что вы создаете локальную переменную Object, для которой требуется 50 байт. Затем вы выделяете переменную-член, которая будет сохраняться на протяжении всего жизненного цикла приложения, для существования которого требуется 200 байт кучи. Если вы выполняете этот процесс снова и снова, вы можете оказаться в ситуации, когда у вас есть тысячи блоков памяти длиной всего 50 байт. Поскольку вам нужно 200 байт для постоянного объекта, вы в конечном итоге облажаетесь и получите исключение OutOfMemory.

Теперь, если вы создали тот же объект String, использовали его, затем сами обнулили его и вызвали System.gc() (также вы можете вызвать Thread.yield(), чтобы дать GC возможность запуститься), у вас будут эти 50 байтов, доступных для создания нового постоянного объекта, предотвращения фрагментации и возможных исключений OutOfMemory.

Это очень простой пример, но если у вас много больших изображений, как в игровом приложении, вы очень быстро столкнетесь с этой ситуацией в мобильном пространстве.

И последнее замечание: с устройствами BlackBerry вам следует избегать вызова сборщика мусора самостоятельно, так как он намного сложнее (он дефрагментирует кучу за вас). Будучи более сложным, он намного медленнее (мы говорим о нескольких секундах за прогон), чем обычные неработающие и грязные сборщики мусора на большинстве устройств.

person Fostah    schedule 28.05.2009

На хорошей современной виртуальной машине обычно не имеет особого смысла вызывать System.gc(). Как правило, никогда не имеет смысла устанавливать для атрибутов значение null, если только это не единственный способ сделать их недоступными.

На менее сложных виртуальных машинах, которые вы можете получить на мобильных устройствах, может иметь смысл обнулить ссылку, если она больше не используется в методе, но все еще находится в области действия. (На современных настольных виртуальных машинах, таких как Hotspot, в этом, как правило, больше нет необходимости — виртуальная машина имеет перед собой ваш код и обычно может определить, собираетесь ли вы по-прежнему использовать локальную ссылку, независимо от области действия.)

Теперь, возвращаясь к System.gc(), верно то, что мобильные виртуальные машины исторически были проще, чем довольно сложные «полноценные» виртуальные машины, к которым мы привыкли, такие как Hotspot. Тем не мение:

  • мобильные виртуальные машины получили широкое распространение в последние годы — пропускная способность объектов, как и другие аспекты производительности, определенно улучшилась на многих устройствах;
  • в любом случае, System.gc() не имеет последовательного, четко определенного поведения. На некоторых устройствах он может вообще ничего не делать; на других, например, на настольных виртуальных машинах, это может вызвать тип сборки мусора, который на самом деле снижает производительность по сравнению с обычной, «постепенной» сборкой мусора, которую виртуальная машина автоматически выполняет во время работы приложения.

Поэтому я бы очень осторожно относился к использованию System.gc().

person Neil Coffey    schedule 22.05.2009

Это большая городская легенда в мире Java, что вызов System.gc() на самом деле надежно что-то сделает для вас. Это не будет.

Это просто предположение, что JVM пытается что-то сделать. Javadoc для метода намеренно двусмыслен в этом отношении.

Другая большая проблема — обнуление ссылок. Когда ссылка выходит за пределы области действия, она уже обнуляется виртуальной машиной, и делать это самостоятельно избыточно и вводит в заблуждение. Если есть другие ссылки, они все еще будут доступны, и ваше задание ничего не сделает (если вы не пойдете и не посетите все остальные доступные ссылки - но тогда какой смысл? это то, что VM уже делает).

Итак, чтобы ответить на ваши вопросы:

  • Установка атрибутов в null редко имеет смысл. Разработайте свое программное обеспечение правильно, чтобы ссылки выходили за рамки, когда вы их больше не используете.
  • Вызов System.gc() редко имеет смысл. Позвольте JVM сделать всю работу за вас — вот почему мы используем виртуальную машину вместо того, чтобы управлять собственной памятью.
  • Да, пусть виртуальная машина управляет вашей памятью, она будет выполнять сборщик мусора, когда это необходимо. Однако если у вас плохо разработанное программное обеспечение, оно может победить сборщик мусора в виртуальной машине. В этом случае отследите утечки памяти и проведите рефакторинг программного обеспечения (проще сказать, чем сделать).
person Edward Q. Bridges    schedule 22.05.2009
comment
Как вы отслеживаете утечки памяти? - person Daniel Moura; 22.05.2009

Все ответы на этот вопрос до сих пор полностью верны, главным образом, вы не можете полагаться на System.gc(), чтобы что-то делать. Это зависит от платформы, и MIDP2 не дает никаких реальных спецификаций того, как он должен себя вести.

Однако обычно он реализуется подходящим образом, хотя вы не можете сказать «этот объект теперь удален» и т. д., я считаю приемлемым и целесообразным использовать этот вызов при определенных обстоятельствах. Например, если вашему приложению необходимо выполнить большое удаление, а затем выделение (например, сброс или изменение состояний), выполнение вызова сразу после этого сообщит виртуальной машине - сейчас самое подходящее время для сбора.

Джеймс

person Community    schedule 11.06.2009

Установка атрибутов в значение null (таким образом, уничтожение некоторых ссылок на объекты) приведет к тому, что GC заявит эти объекты. Может быть, они стали не нужны, и разработчики хотели освободить память?

Я слышал, что не каждая цель J2ME имеет GC. Но если это так, имеет смысл вызвать System.gc(), чтобы сборщик мусора не срабатывал, когда вы делаете что-то в реальном времени.

person alamar    schedule 22.05.2009
comment
Хм, я почти уверен, что это часть спецификации языка Java для виртуальной машины, которая должна иметь сборку мусора, какой бы примитивной или плохой она ни была. Я думаю, вы должны предположить, что вы программируете для платформ, которые придерживаются спецификации. - person Neil Coffey; 22.05.2009
comment
Довольно сложно определить, что должен делать сборщик мусора. Так что ничего не делать - это правильно. Это вопрос качества реализации. JavaCard может быть другим, но я был бы очень удивлен, увидев серьезный JavaME без какой-либо разумной реализации. - person Tom Hawtin - tackline; 22.05.2009
comment
Вызов System.gc() не улучшает поведение систем Java SE в реальном времени, и я не думаю, что это сильно поможет на платформах Java ME. - person Peter Lawrey; 23.05.2009