2010-01-13 2 views
4

Итак, я бегу Java-сервер (в частности Winstone: http://winstone.sourceforge.net/)У Java заканчивается память, хотя я даю ей много!

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

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

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

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

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

на Linux.

Спасибо, Matt

+2

Если эти 8,4 ГБ размещены в «середине» этих 12 ГБ, и программа пытается выделить блок размером 3 ГБ за один раз, может быть, такого не существует такой блок смежных, свободных Память. Это заставляет GC работать, чтобы попытаться освободить некоторые вещи, но если он не сможет освободить достаточно памяти, чтобы найти этот блок, тогда он будет опускаться, хотя он должен технически быть свободным. –

+0

GC должен перемещать память. –

+0

То, что он добавляет, не особо велико. Это куча текстовых файлов (bunch = ~ 25-50 000). Поэтому не похоже, что он пытается выделить большой блок памяти. Хотя, возможно, это поражает некоторые проблемы фрагментации ...? GC должен очистить это, правда? – spitzanator

ответ

0

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

+0

Хороший звонок. Я обновился, но, похоже, это не помогает. – spitzanator

0

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

+0

Ах, извините. Машина имеет 24 гигабайта оперативной памяти. Я выделил 12 на этот процесс и 12 на другой (им обоим нужно 12). Не глупый вопрос вообще. – spitzanator

+0

Но как насчет обмена? У вас есть какое-либо пространство подкачки, или вы полностью работаете из ОЗУ? Если вы работаете полностью из ОЗУ, то, если * Linux * не знает, что он должен выделить 12GB для процесса (и я не уверен, как вы это сделаете), тогда у вас может закончиться физическая память из-за конкуренции с другие процессы. –

+0

На ОЗУ нет соперничества. Я посмотрел, и все еще есть свободная оперативная память, когда java-процесс взрывается. – spitzanator

0

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

+0

Ошибка не в пространстве PermGen, нет.По крайней мере, исключение не сказано ... – spitzanator

8

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

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

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

Предположительно, CPU, нависший на 100%, является сборщиком мусора Java.

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

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

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

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

  • Возможно также (но маловероятно), чтобы кто-то установил лимит процесса. Вы можете использовать команду shell builtin 'ulimit', чтобы убедиться, что это было сделано; см. «man ulimit» для деталей.

EDIT

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

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

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

+0

Hm. Я сомневаюсь, что 8.4-гигабайты используются JVM. Он масштабируется линейно, когда мы открываем файлы, которые я храню в куче. Тем не менее, у меня нет никакого места подкачки. Интересно, может ли это быть. Там также определенно не предел процесса. Есть ли какие-нибудь другие опрятные вещи, которые я могу передать JVM (a la '-Xmx12288M'), чтобы заставить его вести себя так, как хотелось бы (или, по крайней мере, дать мне более четкое представление о том, почему он терпит неудачу)? – spitzanator

+0

Имейте в виду, что простые вещи, такие как str + = otherString; может потребоваться по крайней мере длина (str + otherString) * 2 памяти, если это не может быть выделено, вы получаете исключения oom. Может быть, если str действительно велика. То же самое, если вы перетасовываете массивы для выращивания. Или использовать библиотеки, которые делают это под капотом, вне поля зрения. – nos

+0

@spitzanator: Я ответил на это по вашему вопросу, выше. –

1

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

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

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

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

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

0

нечетная часть является то, что, в соответствии с «сверху», то есть 15,0 г ВИРТ (UAL памяти), и это RES (идент набор) является 8,4 г. Как только он достигает 8,4 г, процессор висит на 100% (хотя он загружается с диска ), и в итоге я получаю Java OutOfMemoryError. Предположительно, CPU , висящий на 100%, - это Java, делающий мусор .

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

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

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

Смежные вопросы