Пишу на J2ME. Сейчас встал вопрос оптимизации. Конкретно — есть класс, для приложения нужен только один объект этого класса. Есть ли смысл все его члены обяъвить статическими?
Как вообще происходит загрузка классов и их членов в память (для динамики и статики), где об этом можно почитать?
Как оптимально спроектировать класс, если члены класса используются только один раз при загрузке приложения? Несколько экземляров этого класса быть не может.
Re: Выделение памяти под динамические и статические члены
Здравствуйте, Donz, Вы писали:
D>Пишу на J2ME. Сейчас встал вопрос оптимизации. Конкретно — есть класс, для приложения нужен только один объект этого класса. Есть ли смысл все его члены обяъвить статическими? D>Как вообще происходит загрузка классов и их членов в память (для динамики и статики), где об этом можно почитать?
Сначала classloader загружает в память байт-код класса, выделяет память под статические переменные и инициализирует их (статичесий конструктор).
При создании экземпляра класса выделяется память под нестатические поля (и вызвается конструктор).
При таком описании проблемы я бы попробовал использовать шаблон Singleton, хотя если можно точно определить точку, когда использование класса больше не является необходимым, то можно и просто за'null'ить все статические поля.
Так как код класса будет всё время висеть в памяти, то относительная разница между этими двумя вариантами будет, скорее весего, незначительной, но использование singleton'а делает обращение к нужным полям более явным.
Хотя есть встречный вопрос — если данный класс используется один раз и только при старте приложения, то действительно ли он нужен?
Re[2]: Выделение памяти под динамические и статические члены
Здравствуйте, DK3981, Вы писали:
DK>Сначала classloader загружает в память байт-код класса, выделяет память под статические переменные и инициализирует их (статичесий конструктор). DK>При создании экземпляра класса выделяется память под нестатические поля (и вызвается конструктор).
Так classloader в какой момент загружает в память байт-код класса? Мне так кажется, что при первом вызове членов этого класса, так?
DK>При таком описании проблемы я бы попробовал использовать шаблон Singleton, хотя если можно точно определить точку, когда использование класса больше не является необходимым, то можно и просто за'null'ить все статические поля. DK>Так как код класса будет всё время висеть в памяти, то относительная разница между этими двумя вариантами будет, скорее весего, незначительной, но использование singleton'а делает обращение к нужным полям более явным.
Насчёт Java SE учту, но у меня конкретно Java ME, нет там такой вещи.
DK>Хотя есть встречный вопрос — если данный класс используется один раз и только при старте приложения, то действительно ли он нужен?
По идее, можно всё запихать и в другой класс, но просто выделив этот функционал в отдельный класс, я могу довольно просто добавлять его в другие приложения.
Re[3]: Выделение памяти под динамические и статические члены
D>Так classloader в какой момент загружает в память байт-код класса? Мне так кажется, что при первом вызове членов этого класса, так?
100%й уверенности нет, но по моему опыту отсутствующий класс грузится в память:
1) При явной загрузки с помощью classForName()
2) При обращении к статическим методам/полям/полю сlass (я не уверен, что по стандарту оно именно поле, но ведёт себя именно так).
3) При создании нового экземпляра класса.
D>Насчёт Java SE учту, но у меня конкретно Java ME, нет там такой вещи.
Это просто такой класс, у которого конструктор — private, и есть специальный метод для получения единственного экземпляра:
public class MySingleton {
private static MySingleton _instance;
public static MySingleton getInstance() {
if (null == _instance) {
_instance = new MySingleton();
}
return _instance;
}
public static void releaseInstance() {
_instance = null;
}
private MySingleton() {
}
}
Re[4]: Выделение памяти под динамические и статические члены
Здравствуйте, DK3981, Вы писали:
D>>Так classloader в какой момент загружает в память байт-код класса? Мне так кажется, что при первом вызове членов этого класса, так?
DK>100%й уверенности нет, но по моему опыту отсутствующий класс грузится в память: DK>1) При явной загрузки с помощью classForName() DK>2) При обращении к статическим методам/полям/полю сlass (я не уверен, что по стандарту оно именно поле, но ведёт себя именно так).
не, не поле. Хак (как и генерики в тигре DK>3) При создании нового экземпляра класса.
D>>Насчёт Java SE учту, но у меня конкретно Java ME, нет там такой вещи.
DK>Это просто такой класс, у которого конструктор — private, и есть специальный метод для получения единственного экземпляра:
Здравствуйте, Lucker, Вы писали:
L>Здравствуйте, DK3981, Вы писали:
D>>>Так classloader в какой момент загружает в память байт-код класса? Мне так кажется, что при первом вызове членов этого класса, так?
DK>>100%й уверенности нет, но по моему опыту отсутствующий класс грузится в память: DK>>1) При явной загрузки с помощью classForName() DK>>2) При обращении к статическим методам/полям/полю сlass (я не уверен, что по стандарту оно именно поле, но ведёт себя именно так).
L>не, не поле. Хак (как и генерики в тигре
Что такое Хак?
DK>>Это просто такой класс, у которого конструктор — private, и есть специальный метод для получения единственного экземпляра:
L>он не про это. Он про отсутствие GC в J2ME.
Не, я именно про это. GC в J2ME есть.
Re[6]: Выделение памяти под динамические и статические члены
L>>не, не поле. Хак (как и генерики в тигре D>Что такое Хак?
Ну в данном случае это сравне препроцессингу. То есть javac при виде в некотором классе конструкцию типа SomeClass.class делает препроцессинг, добавляя к определению класса статическое синтетическое поле и в статическом инициализторе класса (если обращение к SomeClass.class происходит в статик контексте, иначе в дефултном инстансе инициализаторе) инициализирует это поле ссылкой на нужный класс вызывая некий синтетичский метод. Этим, вероятно, и достичается LazyLoading в случае с конструкцией SomeClass.class.
DK>>>Это просто такой класс, у которого конструктор — private, и есть специальный метод для получения единственного экземпляра:
L>>он не про это. Он про отсутствие GC в J2ME.
D>Не, я именно про это. GC в J2ME есть.
ААА. ну не силен в J2ME Просто слышал, что есть некая кас№№№№ная JVM без GC а вот где — ХЗ.
Здравствуйте, Donz, Вы писали:
DK>>Хотя есть встречный вопрос — если данный класс используется один раз и только при старте приложения, то действительно ли он нужен? D>По идее, можно всё запихать и в другой класс, но просто выделив этот функционал в отдельный класс, я могу довольно просто добавлять его в другие приложения.
Я бы не создавал обьект класса, а только определил его параметры статическими, которые инициализируются в блоке static при первом обращении к классу. Вообще, все рекомендации по java performance tuning противоречат правилам хорошего ООП — чем больше статических переменных и меньше обьектов, тем лучше. К статическим переменным легче доступ, а на создание любых обьектов и последующее освобождение памяти от них расходуются существенные ресурсы JVM. А код методов в любом случае хранится в памяти в одном экземпляре.
Re[4]: Выделение памяти под динамические и статические члены
M>Я бы не создавал обьект класса, а только определил его параметры статическими, которые инициализируются в блоке static при первом обращении к классу. Вообще, все рекомендации по java performance tuning противоречат правилам хорошего ООП — чем больше статических переменных и меньше обьектов, тем лучше. К статическим переменным легче доступ, а на создание любых обьектов и последующее освобождение памяти от них расходуются существенные ресурсы JVM. А код методов в любом случае хранится в памяти в одном экземпляре.
Я позволю себе не согласиться.
Чуть выше сказано, что данные требуются только на этапе инициализации приложения.
В случае singleton'а мы получаем постоянно висящие код + 1 указатель, а в случае статических полей — код + память на хранение всех этих полей.
К тому же вариант с singleton'ом позволяет чуть меньше задумываться о правильном сбрасывании всех ссылок на объекты. В случае статических полей всё равно должен существовать метод, который будет явно присваивать null всем полям, и при добавлении ещё одного поля надо будет не забыть упомянуть его в этом методе.
Да и на создание объекта (в данном случае — не более, чем одного) уходит ресурсов не сильно больше, чем на загрузку класса.
С удалением объектов ситуация похожая — GC всё равно должен будет почистить память за объектами, на которые указывали статические поля класса (пока в них была необходимость), так что в данном случае и затраты на удаление объекта можно считать малыми.
Re[4]: Выделение памяти под динамические и статические члены
Здравствуйте, DK3981, Вы писали:
D>>Так classloader в какой момент загружает в память байт-код класса? Мне так кажется, что при первом вызове членов этого класса, так?
DK>100%й уверенности нет, но по моему опыту отсутствующий класс грузится в память: DK>1) При явной загрузки с помощью classForName() DK>2) При обращении к статическим методам/полям/полю сlass (я не уверен, что по стандарту оно именно поле, но ведёт себя именно так). DK>3) При создании нового экземпляра класса.
Еще можно добавить 4) инициализация класса-наследника.
DK>Это просто такой класс, у которого конструктор — private, и есть специальный метод для получения единственного экземпляра.
Насколько я понимаю специфику j2me, основная проблема -- это нехватка памяти для классов загружаемых в телефон. Оптимизации ведутся в основном в сторону уменьшения общего количества классов и кода в них. В связи с этим, полагаю что, синглтоны в j2me менее предпочтительны (поскольку их код этих классов и классов их использующих будет занимать больше места), чем классы со статическими public полями.
С другой стороны, если вдруг захочется создать несколько экземпляров, то с синглтонами проблем будет меньше.
--
Дмитро
Re[5]: Выделение памяти под динамические и статические члены
Здравствуйте, DK3981, Вы писали:
DK>Я позволю себе не согласиться.
DK>Чуть выше сказано, что данные требуются только на этапе инициализации приложения. DK>В случае singleton'а мы получаем постоянно висящие код + 1 указатель, а в случае статических полей — код + память на хранение всех этих полей.
Ну при исользовании singleton'а кроме кода + 1 указателя на объект мы имеем те же поля, только внутри объекта, поэтому память для них все-равно выделяется. Однако, как показывает опыт, задумываться над такой оптимизацией не стоит. Стоит оптимизировать только тогда, когда грабли с производительностью. Опыт крутых дядек говорит что 80% процентов ресурсов занимает 20% кода (то-же справедливо и для распределения памяти). В любом случае жертвовать понимаемостью и удобностью кода можно только когда на это есть очень серьезные причины.
Ввиду отсутствия для j2me IoC контейнеров рекомендую использовать pattern singleton (если есть необходимость глобальной видимости объекта).
Если сохдание одного лишнего объекта приводит к критическому спаду производительности или повышению использования системных ресурсов перейти к статическому классу не составит труда.