Enum vs. Static Constants, объем памяти
Сначала ознакомьтесь с приведенной ниже цитатой из руководства разработчика Android:
-
Для перечислений часто требуется более чем вдвое больше памяти, чем статические константы. Вы должны строго избегать использования перечислений на Android.
-
Каждый класс Java (включая анонимные внутренние классы) использует около 500 байт кода. https://developer.android.com/training/articles/memory.html
Несмотря на зловещее предупреждение в первом пункте "строго избегать использования перечислений на Android", то, что сказано под этим пунктом, на самом деле звучит не так уж плохо. Константы представляют собой 32-битные целые числа, а перечисления - это, вероятно, 64-битные ссылки. Математика, приведенная там, где перечисления в два раза дороже, имеет смысл и не кажется настолько страшным.
Я обеспокоен тем, что предупреждение, отчасти, может быть основано на втором марке.
Я задаюсь вопросом, несет ли простая декларация класса "класс" 500 байтов накладные расходы? Как насчет типа enum enum?
Кажется вполне правдоподобным, что типы могут быть "расширенными классами", поскольку они могут принимать свои собственные методы, а не просто экземпляры. Чтобы сформулировать это как вопрос, если мое перечисление является "Цвет", и у меня есть 20 типов перечисления цвета (например, красный, синий, зеленый...), это 500 байтов на тип?
Ответы
Ответ 1
Enums - это бесконечная дискуссия в мире Android.
Вы можете услышать хороший разговор от Ромена Гая и Чет Хаасе об этом здесь: http://www.parleys.com/play/5298f999e4b039ad2298c9e3/chapter57/about
Согласно этому видео, насколько большой объект в Dalvik может быть рассчитан как:
overhead of Object + overhead of dlmalloc + data + align
- Накладные расходы Объекта равны 8 байтам.
- Накладные расходы dlmalloc могут составлять 4 - 8 байтов (в большинстве случаев это 8
байт)
- Размер данных зависит от данных (конечно)
- Наконец, все должно быть выровнено по 8 байт (например, если у вас есть 12 байт
для объекта это займет 16 байт)
Помните о том, что каждое значение перечисления на самом деле является экземпляром класса Enum.
Еще один важный момент, который следует учитывать, - размер файла dex.
Например, следующее перечисление займет около 1,112 байт.
public static enum Things {
THING_1,
THING_2;
};
Или у вас может быть два статических int, которые будут занимать 128 байт.
public static int THING_1 = 1;
public static int THING_2 = 2;
У вас есть 10-кратное улучшение размера файла dex.
Существует также большое отличие в том, как сгенерирован скомпилированный код dalvik.
Для Enum есть много вещей, которые компилятор делает для вас. Существует статическая инициализация класса при первом запуске класса во время выполнения. Он добавляет сверхурочные при запуске.
С другой стороны, перечисление приносит также много преимуществ: читаемость, удобство использования, безопасный код типа.
Я буду беспокоиться о перечислении только в особых случаях.
Особенно, если учесть, что использование ProGuard может оптимизировать Enums, преобразовывая их в обычные int-константы.
Ответ 2
Вы пропустите прочитанное сообщение.
Вы цитируете
Every class in Java (including anonymous inner classes) uses about 500 bytes of code.
Обратите внимание, что вам нужно сохранить определение класса в некотором месте и занимает 500 байт.
Это означает, что нет разницы между enum Const {}
и class Const{}
.
Что более важно, так это объем памяти, который объекты потребляют при создании экземпляра.
Every class instance has 12-16 bytes of RAM overhead.
- источник следующей строки.
Чтобы обобщить это. Вы можете использовать константы формы в форме значения int только тогда, когда они объявлены в одном длинном контейнере (перечисление или класс).
В действительности enum также является классом, который расширяет тип Enum<?>
, а для экземпляра его требуется больше памяти, чем static int constant.
То, что вы торгуете здесь, - это потребление памяти и тип безопасного кода. Когда вы используете константу, вы не можете гарантировать безопасность типа.
public void doAction(int what) {}
public void doAction(What what) {}
На современных устройствах вы можете кодировать больше памяти. Но для некоторых аспектов вашего кода может быть проще использовать int для других перечислений - правильный выбор. Это особенно заметно в пакете androind R, где сумма кода значительна.
В таком случае вы должны использовать int для небольших доменных полей. Перечисление более безопасно.