Прирост производительности при использовании null, а не значений по умолчанию?

#java #performance #optimization #memory

#java #Производительность #оптимизация #память

Вопрос:

Говорят, что преждевременная оптимизация — это корень всего зла, но вот так…

У нас есть высокопроизводительное приложение; кэш в памяти, поддерживаемый Java на стороне сервера, и то, что должно быть очень быстрым графическим интерфейсом C # на стороне клиента.

Я отмечаю, что в настоящее время объекты, которые мы используем в кэше, имеют значения по умолчанию — например, инициализирующие строки по умолчанию на «» и даты на 1/1/1999 вместо того, чтобы оставлять их нулевыми.

Возможно, я здесь очень привередлив, но разве это не добавляет немного больше места для каждого объекта (как в кэше, так и при сериализации объекта), чем в противном случае, если бы оно было null?

Просто интересно, какого рода улучшения (если таковые имеются) будут достигнуты, когда наши объемы объектов начнут становиться довольно высокими…

Приветствую, Дэйв.

Комментарии:

1. @f1dave: вау… Высокопроизводительное приложение, и вы храните даты в объектах? Момент времени должен храниться в примитиве (скажем, в Java long ) в виде (миллисекунд), прошедших с момента начала эпохи. Это почти всегда верно, особенно если речь идет о производительности. Единственный момент, когда вам нужно «отформатировать» этот момент времени как дату, — это когда какой-то пользователь хочет прочитать его удобным для пользователя способом (скажем, в своем собственном часовом поясе и т.д.).

2. @Аноним. Я вообще не понимаю, как это связано с вопросом производительности.

3. @Kaj — OP спросил о «немного большем пространстве», а не о процессоре.

4. И использование значений по умолчанию (также известных как «шаблон нулевого объекта») обычно предназначено для предотвращения NPE.

5. О, послушайте, конечно, я был бы обеспокоен NPE. Но я на мгновение надеваю свою черную шляпу (дурацкую шляпу, что угодно). @SyntaxT3rr0r — В кэше хранятся объекты. Сами объекты имеют атрибуты, которые настолько просты, насколько это возможно, в основном примитивы. Однако они используют java.util.Date.

Ответ №1:

Преждевременная оптимизация, безусловно, является злом.

Но думать о характеристиках производительности вашего приложения и соответствующих стратегиях проектирования для оптимизации производительности вполне разумно, если производительность является ключевым требованием приложения 🙂

Несколько важных моментов:

  • Есть некоторые (незначительные) преимущества в производительности от использования null вместо значения по умолчанию. Машинному коду проще проверить наличие значения null, чем разыменовывать ссылку на объект и проверять значение этого объекта. Вероятно, вы этого не заметите, если все находится в кэше L1, но если это приводит к отсутствию кэша в высокопроизводительном приложении, это может стать болезненным.
  • Существует некоторая дополнительная нагрузка на память, но это, вероятно, не имеет большого значения — предполагая, что вы повторно используете одни и те же объекты со значением по умолчанию много раз (т. Е. Многие ключи указывают на одно и то же значение), тогда в целом не будет много дополнительных экземпляров объекта.
  • Если ваши значения по умолчанию неизменяемы, одноэлементные объекты, то это очень помогает по трем причинам:
    • Вам нужна только одна копия неизменяемого объекта, а не разные экземпляры «» (String.intern() здесь помогает!)
    • Гораздо более вероятно, что один объект, используемый много раз, будет эффективно кэшироваться
    • Вы можете использовать равенство ссылок (value == DEFAULT_SINGLETON) для проверки значения по умолчанию, что позволяет избежать необходимости разыменования указателя, когда DEFAULT_SINGLETON является статическим конечным значением.
  • Если вы используете неизменяемые одноэлементные значения по умолчанию, будьте очень осторожны, чтобы не подмешать какие-либо другие экземпляры того же значения. Это может произойти, например, при десериализации объектов — вам нужно использовать readResolve() и т.д. чтобы убедиться, что вы получаете правильное значение singleton на месте.

На мой взгляд, вам, вероятно, следует предпочесть null для значений по умолчанию.

  • Это немного быстрее и использует меньше памяти
  • Это, скорее всего, поможет вам обнаружить логическую ошибку (с помощью громкого исключения NullPointerException, а не вызовет трудноотслеживаемую ошибку с использованием значения по умолчанию вместо реального значения)

Комментарии:

1. Приветствую mikera. Да, похоже, мы довольно последовательны в использовании неизменяемых одноэлементных объектов, как вы говорите. И что вы знаете, парень, который написал исходный код, тот, кто просит меня исследовать значения null 😉