Java не хватает памяти, хотя я даю это много! - PullRequest
4 голосов
/ 13 января 2010

Итак, я использую Java-сервер (в частности, Winstone: http://winstone.sourceforge.net/)

Как это: java -server -Xmx12288M -jar /usr/share/java/winstone-0.9.10.jar --useSavedSessions = false --webappsDir = / var / servlets --commonLibFolder = / usr / share / java

В прошлом это работало нормально, но теперь ему нужно загрузить в память гораздо больше, чем раньше.

Странная часть в том, что, согласно 'top', он имеет 15.0g VIRT (пользовательская память), а RES (идентификатор) составляет 8.4g. Как только он достигает 8,4 г, процессор зависает на 100% (даже при загрузке с диска), и в конце концов я получаю Java OutOfMemoryError. Предположительно, зависание процессора на 100% - это сборка мусора в Java.

Итак, мой вопрос: что дает? Я дал ему 12 гигов памяти! И он использует только 8,2 гигабайта, прежде чем выбросит полотенце. Что я делаю не так?

О, и я использую Java-версия "1.6.0_07" Java (TM) SE Runtime Environment (сборка 1.6.0_07-b06) Java HotSpot (TM) 64-разрядная серверная виртуальная машина (сборка 10.0-b23, смешанный режим)

в Linux.

Спасибо, Matt

Ответы [ 6 ]

8 голосов
/ 13 января 2010

Странная часть в том, что, согласно 'top', он имеет 15.0g VIRT (пользовательская память), а RES (идентификатор) составляет 8.4g. Как только он достигает 8,4 г, процессор зависает на 100% (даже при загрузке с диска), и в конце концов я получаю Java OutOfMemoryError.

Я думаю, что вы неправильно истолковываете вещи. Опция "-Xmx12288M" не резервирует физическую память. Скорее, он устанавливает верхний предел размера кучи Java. Java также нуждается в памяти для объектов без кучи; например пространство пермгена, пространство кода, отображенные в память файлы и так далее. Вполне вероятно, что куча 12 г + память без кучи, используемая / совместно используемая JVM для добавления до 15 г.

8.4g, сообщаемое top как RES - это объем физической памяти, который в данный момент используется для запуска JVM. Это не имеет прямого отношения к размеру вашей кучи Java. В самом деле, можно ожидать, что число RES будет расти и уменьшаться по мере того, как система виртуальной памяти ОС выгружает и выгружает страницы различных процессов. Это полностью вне контроля JVM.

Предположительно, зависание процессора на 100% - это сборка мусора в Java.

Да. Обычно так и происходит.

Я могу придумать три возможных объяснения:

  • Скорее всего, операционная система не может предоставить вашей JVM требуемую память, так как недостаточно места на диске подкачки. Например, если у вас есть 2 процесса с 15 г виртуальной памяти каждый, это 30 ГБ. Учитывая, что у вас есть 24 г физической памяти, вам потребуется как минимум 8 г (возможно, больше) пространства подкачки. Если объем физической памяти, выделяемой для пользовательских процессов +, объем пространства подкачки меньше, чем общее виртуальное пространство, используемое процессами, ОС начнет отклонять запросы JVM на расширение кучи. Вы можете запустить «swapon -s», чтобы увидеть, сколько места подкачки доступно / используется.

  • Ваше приложение может действительно использовать все 12 г кучи, которые, как вы сказали, оно может использовать, но этого недостаточно. (Может быть, у вас утечка памяти. Может, ей действительно нужно больше памяти.)

  • Также возможно (но весьма маловероятно), что кто-то установил ограничение процесса. Вы можете использовать встроенную команду оболочки ulimit, чтобы увидеть, было ли это сделано; обратитесь к "man ulimit" за подробностями.

РЕДАКТИРОВАТЬ

  • Если вы используете опции -verbose:gc и -XX:+PrintGCDetails, сборщик мусора может дать вам больше подсказок о том, что происходит. В частности, он скажет вам, насколько велика куча Java, когда у вас заканчивается память.

  • Вы можете написать небольшое Java-приложение, которое просто выделяет и не освобождает много памяти, и посмотрите, сколько ему удастся выделить, прежде чем упасть с ошибкой OOM при запуске с теми же параметрами, что и у вас в данный момент. с помощью. (Я не думаю, что это скажет вам что-то новое. РЕДАКТИРОВАТЬ 2 на самом деле, оно скажет вам что-то, если вы запустите его так, как предлагает @Dan!)

  • Если (как представляется вероятным) реальная проблема заключается в том, что у вас недостаточно места подкачки, вы ничего не можете сделать на стороне Java, чтобы это исправить. Вам нужно перенастроить вашу систему, чтобы иметь больше места подкачки. Обратитесь к документации по системному администрированию Linux, страницам man для swapon, mkswap и так далее.

1 голос
/ 25 апреля 2010

Иногда OutOfMemorError не означает, что куча объектов израсходована, а что-то еще. Была ли какая-либо другая информация о стеке ошибок?

В частности, JVM нужна группа памяти / адресного пространства, отдельная от пространства кучи. В какой-то момент, предоставив процессу больше кучи объектов, можно оставить меньше места для этого другого пула - как это ни парадоксально, сделать OOME более вероятным с большими настройками '-Xmx'!

Отображенные в память файлы могут занимать много адресного пространства; Неспособность закрыть файлы должным образом может оставить это место выделенным до GC / финализации, что происходит в непредсказуемое время. Кроме того, большая куча отодвигает GC / финализацию - это означает, что это собственное адресное пространство может оставаться зарезервированным дольше, и снова: большие кучи могут означать более частые OOME из-за истощения другой памяти.

Вы также можете использовать '-Xms' с тем же значением, чтобы принудительно захватить все адресное пространство кучи при запуске - возможно, вызвать сбой на более удобной / понятной / воспроизводимой стадии. * +1007 *

Наконец, есть также порог, при котором генерируется OOME, даже если ни один запрос памяти не завершился - но GC отнимает «слишком много» времени, указывая на то, что мусор создается так же быстро, как он собирается, вероятно, в узком цикле , Это может привести к большой неэффективной загрузке с диска, где создается много мусора для небольшого количества сохраняемых данных. Посмотрите [ограничение накладных расходов GC] для деталей.

0 голосов
/ 25 апреля 2010

Странная часть в том, что, согласно «верх», он имеет 15,0 г VIRT (ед. память), и это RES (идентификационный набор) 8,4 г. Как только он достигает 8,4 г, процессор зависает на 100% (даже если он загружается из диск), и в конце концов, я получаю Java OutOfMemoryError. Предположительно, процессор на 100% висит это Java делает мусор коллекция.

Я бы предположил, что java должен использовать столько памяти, сколько он решает (или вынужден) использовать на диске для ваших данных. Теперь в следующий раз, когда он должен собрать мусор, он должен использовать IO для этого. Сбор мусора на диске наверняка довольно дорог. А поскольку у вас столько объектов, сборщик мусора может запрыгивать снова и снова. Это может быть причиной того, что ваш процессор на 100% ... выполняет сборку мусора навсегда.

Как сказал Стивен -бербос: gc и -XX: + PrintGCDetails даст больше подсказок.

Но кроме этого, может быть, будет полезно инвестировать в реализацию, которая не должна загружать все файлы одновременно? Работа на пределе вашей памяти не выглядит как выигрышная стратегия.

0 голосов
/ 13 января 2010

И просто чтобы подтвердить, что пространство PermGen не заканчивается, верно?

0 голосов
/ 13 января 2010

Возможно, глупый вопрос, но вы уверены, что ваш раздел подкачки имеет как минимум 15 ГБ свободного места при запуске программы?

0 голосов
/ 13 января 2010

Можете ли вы обновить до последней версии Java (1.6.0_17)?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...