Является ли инкапсуляция строк как byte [] для экономии памяти?(Джава) - PullRequest
6 голосов
/ 30 июля 2010

Недавно просматривал некоторый код Java Swing и увидел это:

byte[] fooReference;

String getFoo() {
   returns new String(fooReference); 
}

void setFoo(String foo) {
  this.fooReference = foo.getBytes();
}

Вышесказанное может быть полезно для экономии места на вашей памяти или, как мне сказали.

Является ли этот перебор кем-то еще, инкапсулируя свои строки таким образом?

Ответы [ 8 ]

31 голосов
/ 30 июля 2010

Это действительно, действительно плохая идея. Не используйте кодировку платформы по умолчанию. Нечего сказать, что если вы позвоните setFoo, а затем getFoo, вы получите те же данные.

Если вы должны сделать что-то подобное, тогда используйте UTF-8, который наверняка может представлять весь Unicode ... но я бы на самом деле не стал этого делать. Он потенциально экономит некоторую память, но за счет выполнения преобразований в большинстве случаев без необходимости - и подвержен ошибкам с точки зрения отказа от использования соответствующей кодировки.

Осмелюсь сказать, что есть некоторые приложения, где это было бы уместно, но для 99,99% из них это ужасная идея.

10 голосов
/ 30 июля 2010

Это не очень полезно:1. Вы копируете строку каждый раз при вызове getFoo или setFoo, увеличивая тем самым использование процессора и памяти2. Это неясно

5 голосов
/ 30 июля 2010

Небольшая историческая экскурсия ...

Использование байтовых массивов вместо объектов String фактически имело некоторые существенные преимущества в первые дни Java (1.0 / 1.1), если вы были уверены, что вам никогда не понадобится что-либо за пределами ISO-8859-1. С виртуальными машинами того времени было более чем в 10 раз быстрее использовать drawBytes () по сравнению с drawString (), и это действительно экономит память, которая в то время была все еще очень скудной, а апплеты имели жестко закодированный барьер памяти 32 и позже 64 МБ в любом случае. Мало того, что byte [] меньше встроенного char [] объектов String, но вы также можете сохранить сам сравнительно тяжелый объект String, который действительно имеет значение, если у вас много коротких строк. Кроме того, доступ к массиву простых байтов также быстрее, чем использование методов доступа String со всеми проверками их дополнительных границ.

Но поскольку drawBytes перестала работать быстрее в Java 1.2 и поскольку текущие JIT намного лучше, чем Symantec JIT того времени, оставшееся минимальное преимущество в производительности массивов byte [] над строками больше не стоит хлопот. Преимущество памяти все еще есть, и, таким образом, оно все еще может быть вариантом в некоторых очень редких экстремальных сценариях, но в настоящее время это не следует учитывать, если в этом нет особой необходимости.

3 голосов
/ 30 июля 2010

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

3 голосов
/ 30 июля 2010

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

2 голосов
/ 30 июля 2010

Это действительно не имеет никакого смысла. Если бы это была постоянная времени компиляции, которую вам не нужно возвращать обратно в String, то это имело бы бит больше смысла. У вас все еще есть проблема с кодировкой символов.

Для меня было бы больше смысла, если бы это была char[] константа. В реальном мире существует несколько JSP-компиляторов, которые оптимизируют строковые константы в char[], что, в свою очередь, может легко записываться в Writer#write(char[]). Это, наконец, «немного» более эффективно, но эти маленькие кусочки имеют большое значение в больших и интенсивно используемых приложениях, таких как Google Search и т. Д.

JSP-компилятор Tomcat Jasper также делает это. Проверьте настройку genStringAsCharArray. Это тогда нравится так

static final char[] text1 = "some static text".toCharArray();

вместо

static final String text1 = "some static text";

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

2 голосов
/ 30 июля 2010

Каждый вызов getFoo () создает новую строку.Как это экономит память?Во всяком случае, вы добавляете дополнительные издержки для сборщика мусора, чтобы очистить эти новые экземпляры, когда эти новые ссылки станут не ссылаться

1 голос
/ 30 июля 2010

Если после профилирования вашего кода вы обнаружите, что использование памяти для строк является проблемой, вам гораздо лучше использовать обычный строковый компрессор и хранить сжатые строки, чем пытаться использовать строки UTF-8 для незначительного сокращенияв космосе они дают вам.Со строками на английском языке вы можете сжать их до 1-2 бит на символ;большинство других языков, вероятно, похожи.Получить <1 бит на символ сложно, но возможно, если у вас много данных. </p>

...