Реальные различия между «java-server» и «java -client»?

Есть ли реальная практическая разница между «java-server» и «java -client»? Все, что я могу найти на сайте Sun, – это неопределенный «-сервер запускается медленнее, но должен работать быстрее». Каковы реальные различия? (В настоящее время используется JDK 1.6.0_07).

Это действительно связано с HotSpot и значениями по умолчанию ( параметры Java HotSpot VM ), которые отличаются между конфигурацией клиента и сервера.

Из главы 2 технического документа ( Архитектура движка производительности Java HotSpot ):

JDK включает в себя два варианта виртуальной машины – клиентское предложение и виртуальную машину, настроенную для серверных приложений. Эти два решения совместно используют базовую среду кода среды исполнения Java HotSpot, но используют разные компиляторы, которые подходят для совершенно уникальных характеристик производительности клиентов и серверов. Эти различия include в себя компиляцию, определяющую политику и значения по умолчанию для кучи.

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

Компилятор клиентской VM служит обновлением как для classической виртуальной машины, так и для компиляторов «точно в срок» (JIT), используемых предыдущими версиями JDK. Клиентская VM обеспечивает улучшенную производительность во время выполнения приложений и апплетов. Клиентская виртуальная машина Java HotSpot специально настроена для сокращения времени запуска приложений и использования памяти, что делает его особенно подходящим для клиентских сред. В целом, клиентская система лучше подходит для графических интерфейсов.

Таким образом, реальная разница также находится на уровне компилятора:

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

VM сервера содержит усовершенствованный адаптивный компилятор, который поддерживает многие из тех же типов оптимизаций, которые выполняются путем оптимизации компиляторов C ++, а также некоторые оптимизации, которые не могут быть выполнены традиционными компиляторами, такие как агрессивная вставка между вызовами виртуального метода. Это конкурентное преимущество и преимущество перед статическими компиляторами. Адаптивная технология оптимизации очень гибка в своем подходе и обычно превосходит даже продвинутые методы статического анализа и компиляции.

Примечание. Релиз обновления jdk6 10 (см. « Примечания к выпуску обновлений: изменения в версии 1.6.0_10» ) попытался улучшить время запуска, но по другой причине, чем параметры «горячей точки», по-разному упакованы с гораздо меньшим kernelм.


Г. Демекки отмечает в комментариях, что в 64-битных версиях JDK опция -client игнорируется в течение многих лет.
См. java Windows java :

 -client 

Выбирает виртуальную машину клиента Java HotSpot.
64-разрядная версия JDK в настоящее время игнорирует этот параметр и вместо этого использует виртуальную машину Java Hotspot .

Наиболее очевидной непосредственной разницей в более старых версиях Java будет память, выделенная для -client в отличие от приложения- -server . Например, в моей системе Linux я получаю:

 $ java -XX:+PrintFlagsFinal -version 2>&1 | grep -i -E 'heapsize|permsize|version' uintx AdaptivePermSizeWeight = 20 {product} uintx ErgoHeapSizeLimit = 0 {product} uintx InitialHeapSize := 66328448 {product} uintx LargePageHeapSizeThreshold = 134217728 {product} uintx MaxHeapSize := 1063256064 {product} uintx MaxPermSize = 67108864 {pd product} uintx PermSize = 16777216 {pd product} java version "1.6.0_24" 

по умолчанию для -server , но с параметром -client я получаю:

 $ java -client -XX:+PrintFlagsFinal -version 2>&1 | grep -i -E 'heapsize|permsize|version' uintx AdaptivePermSizeWeight = 20 {product} uintx ErgoHeapSizeLimit = 0 {product} uintx InitialHeapSize := 16777216 {product} uintx LargePageHeapSizeThreshold = 134217728 {product} uintx MaxHeapSize := 268435456 {product} uintx MaxPermSize = 67108864 {pd product} uintx PermSize = 12582912 {pd product} java version "1.6.0_24" 

поэтому с -server большинство ограничений памяти и начальных распределений намного выше для этой версии java .

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

Помните также, что вы можете увидеть все детали работающего jvm с помощью jvisualvm . Это полезно, если у вас есть пользователи, которые или модули, которые устанавливают JAVA_OPTS или используют сценарии, которые изменяют параметры командной строки. Это также позволит вам контролировать, в режиме реального времени, использование кучи и пространства сменного пространства, а также множество других характеристик.

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

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

введите описание изображения здесь

Мы запускаем следующий код с помощью обоих переключателей:

 package com.blogspot.sdoulger; public class LoopTest { public LoopTest() { super(); } public static void main(String[] args) { long start = System.currentTimeMillis(); spendTime(); long end = System.currentTimeMillis(); System.out.println("Time spent: "+ (end-start)); LoopTest loopTest = new LoopTest(); } private static void spendTime() { for (int i =500000000;i>0;i--) { } } } 

Примечание . Код компилируется только один раз! В обоих проходах classы одинаковы!

С -client:
java.exe -client -classpath C: \ mywork \ classes com.blogspot.sdoulger.LoopTest
Продолжительность: 766

С-сервером:
java.exe -server -classpath C: \ mywork \ classes com.blogspot.sdoulger.LoopTest
Время, проведенное: 0

Похоже, что более агрессивная оптимизация серверной системы удаляет цикл, поскольку он понимает, что он не выполняет никаких действий!

Справка

Документация Oracle онлайн предоставляет некоторую информацию для Java SE 7.

На java – странице запуска приложений Java для Windows, опция -client игнорируется в 64-разрядном JDK:

Выберите виртуальную машину клиента Java HotSpot. 64-разрядная версия jdk в настоящее время игнорирует эту опцию и вместо этого использует виртуальную машину Java HotSpot.

Однако (чтобы сделать что-то интересное), под- -server говорится:

Выберите виртуальную машину Java HotSpot. В 64-разрядной версии jdk поддерживается только VM Java HotSpot Server, поэтому опция -server неявно. Это может быть изменено в будущей версии.

Страница « Обнаружение машины на сервере» предоставляет информацию о том, какая виртуальная машина выбрана ОС и архитектурой.

Я не знаю, насколько это относится к JDK 6.

IIRC сервер VM делает больше оптимизаций точек доступа при запуске, поэтому он работает быстрее, но занимает немного больше времени для запуска и использует больше памяти. Клиентская VM отключает большую часть оптимизации, чтобы обеспечить быстрый запуск.

Редактировать, чтобы добавить: Вот информация от Sun, это не очень специфично, но даст вам некоторые идеи.

Из Goetz – Java параллелизм на практике:

  1. Отладка: для серверных приложений обязательно указывайте ключ командной строки -server JVM при вызове JVM, даже для разработки и тестирования . Сервер JVM выполняет большую оптимизацию, чем клиентская JVM, такая как переключение переменных из цикла, которые не изменяются в цикле; код, который может работать в среде разработки (клиентская JVM), может быть поврежден в среде развертывания (сервер JVM). Например, если бы мы «забыли» объявить переменную спящей как volatile в листинге 3.4, сервер JVM мог бы вытащить тест из цикла (превратив его в бесконечный цикл), но клиентская JVM не будет . Бесконечный цикл, который проявляется в развитии, намного менее дорогостоящий, чем тот, который появляется только в производстве.

Листинг 3.4. Считать овец.

volatile boolean asleep; ... while (!asleep) countSomeSheep();

Мой акцент. YMMV

IIRC, он включает в себя страtagsи сбора мусора. Теория заключается в том, что клиент и сервер будут отличаться в терминах короткоживущих объектов, что важно для современных алгоритмов GC.

Вот ссылка на режим сервера. Увы, они не упоминают клиентский режим.

Вот очень подробная ссылка на GC в целом; это более простая статья . Не уверен, что любой адрес -сервер vs -client, но это релевантный материал.

В «No Fluff Just Stuff» Кен Сип и Гленн Ванденбург прекрасно справляются с этим.

Я не заметил никакой разницы во времени запуска между двумя, но очень медленно улучшил производительность приложения с помощью «-сервера» (сервер Solaris, каждый из которых использует SunRays для запуска приложения). Это было менее 1,5.

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

IIRC:

  • Куча серверов VM имеет различное количество поколений, чем клиентская VM, и другой алгоритм сбора мусора. Возможно, это не так.
  • VM сервера будет выделять память и не выводить ее в ОС
  • VM сервера использует более сложные алгоритмы оптимизации и, следовательно, имеет больше требований к времени и памяти для оптимизации

Если вы можете сравнить две виртуальные машины Java, один клиент, один сервер, использующий инструмент jvisualvm , вы должны увидеть разницу в частоте и эффекте сбора мусора, а также в количестве поколений.

У меня была пара скриншотов, которая показала разницу действительно хорошо, но я не могу воспроизвести, поскольку у меня 64-разрядная JVM, которая только реализует виртуальную машину сервера. (И я не могу потрудиться, чтобы загрузить и пререкаться с 32-разрядной версией в моей системе.)

Похоже, что это не так, попробовав запустить какой-то код на windowsх с виртуальными машинами на сервере и на клиенте, я, похоже, получаю одну и ту же модель генерации для обоих …

При переносе с версии 1.4 на 1.7 («1.7.0_55»). Мы заметили, что нет таких различий в значениях по умолчанию, назначенных параметрам heapsize | permsize | ThreadStackSize в режиме клиент и сервер.

Кстати, ( http://www.oracle.com/technetwork/java/ergo5-140223.html ). Это fragment, взятый из ссылки выше.

 initial heap size of 1/64 of physical memory up to 1Gbyte maximum heap size of ¼ of physical memory up to 1Gbyte 

ThreadStackSize выше в 1.7, а через Open JDK форум, есть дискуссии, в которых размер кадра несколько выше в версии 1.7. Считается, что реальную разницу можно измерить во время выполнения на основе вашего поведения вашего приложения

Давайте будем гением компьютера.