Как стать автором
Обновить

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

НЛО прилетело и опубликовало эту надпись здесь
Ни разу не слышал от java-программистов, что джава тормозит, в том числе и от тех, кто перешел на джаву с C++.
Множество различных алгоритмов сборки мусора, проект real-time java, а так же постоянное улучшение железа рано или поздно приведут к «равноправности» джава и более низкоуровневых языков. Естественно последние будут быстрее, но будет ли это заметно — уже совсем другой вопрос…
String a = «hello»;
// делаем чего-нибудь
a = null;
При этой операции сама строка «hello» никуда из памяти не денется. Ибо это вообще константная строка, которая загружается раз и навсегда при загрузке класса. Так что хипа от операции «a = null» больше не станет. И фрагментация хипа существено не изменится.
Какая еще к чертям 'константная строка'!? Вы вообще знаете что такое язык Java?
Compile-time constrant expression имелось в виду наверное. Которая закидывается в пул строк в PermGen-e и там лежит.
Зачем выдумывать непонятно что?! согласно спецификации java будет создан объект String со значением «hello». на этот объект указывает ссылка a. вот и все! констант в java как таковых нет! «Compile-time constrant expression» все что мне приходит в голову на это — так не более как final переменная.
я принимаю претензию о неверной терминологии. я имел в виду, что объект типа String будет создан на стадии загрузки класса и не будет выгружен. далее в программе манипуляции типа String a=«hello»; String b=a; a=null; b=«world»; b=null; ничего с хипом не делают вообще(!). Перечитайте оригинальную статью начиная со слов «Давайте посмотрим на пример. Допустим, у нас есть следующий код:» и посмотрите на код.
Перечитал. Конструкции String a = «hello» и b = «world» размещают в heap два объекта класса String. почему ничего с хипом не происходит?! возможно автору надо бы добавить фразу при описании работы алгоритма, что-то типа: если активизируется сборщик мусора после таких строк… А так все грамотно и правильно вцелом написано!
побойтесь бога! если бы конструкция String a=«hello»; размещала бы (на этапе рантайма программы, разумеется) в хипе новый объект типа String, то откуда вообще в этом стринге возьмутся последовательно составленные символы h-e-l-l-o? Дело как раз в том и состоит, что код навроде вот такого никаким боком ничего не меняет в хипе

public void foo ( )
{
  while ( true )
  {
    String a = "hello";
    String b = "apple";
    String c = "banana";
    String d = "apricot";
    String e = "pear";
//
    a = null;
    b = null;
    c = null;
    e = null;
  }
}

в отличии от вот такого:
public void bar ( )
{
  while ( true )
  {
    String a = new String ( "hello" );
    String b = new String ( "apple" );
    String c = new String ( "banana" );
    String d = new String ( "apricot" );
    String e = new String ( "pear" );
//
    a = null;
    b = null;
    c = null;
    e = null;
  }
}

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

String a = «hello»;

и

String a = new String ( «hello» );

Желательно с ссылками на офф. документацию!
разница в том, что первый вариант — это оператор присваивания, а второй — создание нового объекта в хипе (который впоследствии может быть и удален из хипа) ну и присваивание тоже. возьмите декомпилятор и проверьте. от присваивания переменной [допустимого для ее типа] значения размер хипа и его фрагментация не изменяется. Не знаю как найти в официальной документации по жаве такую банальную вещь. Предлагаю вам самостоятельно проверить и аргументированно опровергнуть, если вас что-то в моих словах не устраивает. В конце концов, ну запустите вы фуу и бар и посмотрите как будет вести себя хип и как будет работать GC
вы неправильно перевели «is equivalent to:»
правильный перевод на русский этого будет «эквивалентен по полученным результатам» (именно эквивалентен, а не равен), но это вовсе не означает что конструкции будут «одинаковыми по манере исполнения java-машиной».

конструкция
int i = 5;
тоже эквивалентна конструкции
int i = Integer.parseInt ( new StringBuffer ( )
  .append ( '5' ).toString ( ) );
, но в первом случае — это простое присваивание переменной, а во втором создание объектов в хипе.
Учи Java, чувак
Сам учи, мудак!
Кажется, не все из тех, кто пытается рассказать о GC знают, о чём говорят :)
«При каждом создании объекта JVM будет «класть» некоторый набор данных в PG» — ерунда какая, в permgen хранятся классы и некоторые другие постоянные данные, типа пула для String.intern(). При каждом создании объекта ничего туда не кладётся, конечно.
«One of the things the JVM uses this space for is keeping metadata about the objects you create. So every time you create an object, the JVM will store some information in the permanent generation. „

Из оригинала. Возможно, именно об этих “некоторых других постоянных данных» и шла речь.
Я верю, что оригинал переведён верно, но тем не менее, в permgen хранятся классы.
Так что, для того, чтобы при каждом создании объёкта что-то сохранялось в permgen, нужно, чтобы каждый раз создавался объект нового класса, или делался String.intern() для новой строки :)
согласен, этот «пассаж» меня тоже немного покарябал. В PermGene содержится в основном данные о классах, так что если приложение большое и использует много библиотек вне стандартного java runtime (rt.jar), то нужно и пермген соответственно увиличивать. К примеру, в приложении с hibernate, spring, birt и еще с чем-нибудь (скажем, кучей jsp, плюс классы аппсервера) стандартного PG с его 64MB никак не хватит.
Шикарно! А можете доходчиво объяснить разницу между разными GC?
Об этом я ещё обещался в ноябре сделать пост, да не срастается как-то, обхожусь пока мини-заметками. Погуглю, если встречу соответствующий материал(-ы), обязательно переведу.
Спасибо!!! Очень интересная и полезная статья, как раз сейчас ковыраюсь с visualvm.
Недавно ехал на работу, на светофоре впереди стоит машина с номером х800мх. 800 метров выделил себе мужик, подумал я.
Прочитал. Статья хорошая, спасибо за перевод.

Соответственно, чем больше вы создаете объектов, тем больше «жилого пространства» требуется в PG.

Мне казалось, что чем больше объектов разных типов создается, тем больше требуется пространства. Поскольку, как верно было сказано, в PermGen'е хранятся метаданные.
Если еще точнее, чем больше классов загружается.
Да, про PermGen автор ерунду написал.
Недавно была проблема с относительно большим приложением (dspace), никак не могли понять — то работает, то не работает, то тормозит, то подвисает и tomcat перезапускается по 20 минут или вообще не перезапускается.

Оказывается не хватало permgen, только тогда и узнал о его существовании. Увеличили его — всё прошло.

Удивлён существованием jvisualvm, спс.
Так же помимо размера permgen иногда помогает -XX:NewRatio который отвечает за молодое поколение

основной принцип работы gc:
заполнился eden? — чистим мертвецов, выживших закидываем в survivor
заполняется survivor? — меняем местами 2 наших слота survivor (с полным работаем, свободный становится активным, пошло заполнение с eden), вышившие в old
заполнился old? — ну тут уже глобал счастье, курите все пока мы разбираемся с мусором (а при большом heap дело нешустрое)

Основное правило явы «живи быстро, умри молодым», в случае недостаточного количества под young не выполняется.
По умолчанию выделяется достаточно низкий уровень, в итоге под нагрузкой eden забивается моментом, survivor тоже оказывается заполненный, а следовательно объект сразу попадает в old.

В итоге имеем ситуацию:
1. eden дёргается сборщиком мусора практически непрерывно, доп нагрузка на проц.
2. данные перетекают сразу в old, хотя уже в следующий момент оказываются мертвы и лишь занимают память, когда же заполниться old, то сборка по нему это уже совсем другая история с нагрузками на проц.

увеличивая размер eden имеем
1. eden заполняется постепеннь, выжившие зачастую влезают в survivor, так как те кто там уже были к этому времени почти все поумирали
2. old заполняется уже намного медленнее, следовательно глобальный сборщик запуститься позже или отработает меньше времени.

хотя слишком усердствовать тоже не надо, так как алгоритмы сборки мусора по old более оптимальны по скорости сборки и под большие объёмы, во всём нужно искать середину.
Спасибо за разъяснения. Непонятка только с NewRatio. В статье сказано, что:
-XX:NewRatio=3 — определяем размер old generation большим в три раза чем размер new generation


а нам наоборот, хочется eden сделать больше. Как тогда? И размер eden указывается только относительно old или в абсолютных величинах тоже можно указать?
image
-XX:MaxNewSize
Да, но при этом young generation разделяется на 3 секции, регулируются ли сами секции?
Проблема с кончающимся PermGen довольно популярная. Чтобы решить ее раз и навсегда, сейчас идет работа по ликвидации PermGen вовсе. Метаданные классов будут размещаться в native heap (проще говоря, в памяти, выделяемой malloc'ом).
НЛО прилетело и опубликовало эту надпись здесь
Нет, в релизе JDK7 этого точно не будет. Вероятно, в одном из последующих апдейтов.
Сейчас JVM ничего особо крупного в native heap не сохраняет (разве что CodeCache), поэтому и средств контроля не предоставляет. Когда туда перекочуют метаданные, будет и способ отслеживать через JMX API.
НЛО прилетело и опубликовало эту надпись здесь
Простое увеличение heap в такой ситуации тоже может помочь, т.к. eden увеличится. Другое дело, что heap до бесконечности не увеличишь, у меня в winxp уже при -Xms1400M -Xmx1400M jvm не запускается.

В нашем случае увеличение heap нам никак не помогало (newratio не трогали), а увеличение permsize сразу всё решило.
да, увеливая размер хипа мы автоматически увеличиваем размед и eden, вот только нередко видел ситуации с 1.5G под old и 12M под eden, из параметров были только -Xmx1500m. поведение думаю вы себе представляете.

по поводу тормозов при нехватке permgen, то тут уже сама ява машина должна была ругаться усиленно в лог «java.lang.OutOfMemoryError: PermGen space», что уже должно было насторожить.

пост отписал не к тому что вы что-то неправильно делали, а к тому, что помимо permgen бывают различные ситуации, и к каждой проблеме нужно подходить внимательно.
в избранное
Есть хорошая доходчивая статья (whitepaper) про Garbage Collection от Sun. И с картинками, и с рекомендациями.
И наконец есть целая серия хороших и качественно переведённых статей на IBM developer works. Вот например: www.ibm.com/developerworks/ru/library/j-jtp01274/

Там правда нету весёлых картинок про visual vm, которые, кажется, были основной целью обсуждаемой статьи.
Спасибо, попробовал, интересно.
Что-то насколько я помню, копирующий сборщик мусора не останавливает все потоки. Отстанавливает serial collector, который прибирает tenured gen. Так?
Автор оригинала почему-то умолчал, каким образом отмечаются мертвые объекты, а именно о том что отмечаются все, а потом проходом по графу ссылок стираются метки с живых. Не самый маловажный, казалось бы, факт с точки зрения как производительности так и наглядности.
Автор, у вас первая картинка и последняя картинка одинаковые.
>> В логе можно увидеть, что происходило в JVM — обратите внимание, что использовался алгоритм Concurrent Mark Sweep Compact Collection algorithm (CMS)

Слово Compact в расшифровке CMS — лишнее. CMS как раз не выполняет Compact, за счет чего и позволяет делать только небольшие stop-the-world паузы. Но из-за этого ему приходится управлять памятью с помощью free lists, что создает некоторый дополнительный оверхед и вызывает дефрагментацию памяти.
Есть такой вопросик, не знаю, связан ли он с GC. Что делает флаг "-server" у JVM?
С флагом "-server" дольше осуществляется запуск, так как происходит полная JIT компиляция запускаемого приложения. Без этого флага компиляция осуществляется лишь частично и JVM работает в режиме интерпретатора.

К GC отношения флаг не имеет
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории