что, кроме объектов Class, хранится в Perm Gen Space (солнце 1.6 ВМ)? - PullRequest
15 голосов
/ 14 июня 2011

Я вижу 'java.lang.OutOfMemoryError: пространство PermGen' при выполнении ~ 300 тестов JUnit и использовании контекста Spring.Трудно понять, что съедает PermGen, поскольку:

  • в устойчивом состоянии приложение потребляет около 90 м пространства permgen
  • Я пробовал -XX: MaxPermSize = 256 м для единицытесты - все еще заканчиваются
  • С включенными -XX:+TraceClassLoading и -XX:+TraceClassUnloading я не вижу дополнительных событий "загрузки" при выполнении последних 20-30 тестов перед OutOfMemoryError.

Последнее, похоже, предполагает, что что-то кроме объектов Class заполняет PermGen, нет?Если так, что это могло быть?Например, существуют ли обстоятельства, когда экземпляры класса хранятся в PermGen?

Вот моя информация о виртуальной машине:

$ java -version
java version "1.6.0_25"
Java(TM) SE Runtime Environment (build 1.6.0_25-b06)
Java HotSpot(TM) 64-Bit Server VM (build 20.0-b11, mixed mode)

related

FWIW, корень моей проблемы, которая ускорила этот пост, оказался несколько тривиальным: я предположил, что плагин Maven Surefire наследует настройки виртуальной машины от MAVEN_OPTS (или экземпляра виртуальной машины, выполняющей mvn), когда он разветвляет виртуальную машину - это делаетне (бу)Нужно указать те, которые явно используют argLine в конфигурации плагина.НТН.

Ответы [ 3 ]

4 голосов
/ 14 июня 2011

Иногда злоупотребление String.intern () может вызывать ошибки пространства PermGen из-за того, что интернированные экземпляры String хранятся в PermGen.

Это может быть то, что вы видите - попробуйте исключить ненужные вызовы String.intern (), чтобы увидеть, решит ли это проблему. В общем, я бы не рекомендовал использовать String.intern (), если вы не уверены, что оба из следующих условий верны:

  • Вы уверены, что будет добавлено только ограниченное количество строк
  • Вам действительно нужны такие строки, чтобы совместно использовать одну и ту же идентификацию объекта (например, если много экземпляров одинаковых строк будут занимать недопустимые объемы памяти или вам нужно полагаться на == для сравнения строк по сложным причинам производительности)
2 голосов
/ 14 июня 2011

Interned Strings также хранятся в permgen, хотя сотни мегабайт строк строки маловероятны. Помните, что каждый Spring Bean, для которого вы используете прокси, генерирует новые классы на лету для реализации интерфейсов, которые вы используете. (Или ваши классы, если вы используете прокси-серверы CGLIB и т. Д.) Поэтому, если вы создаете «свежий» Spring ApplicationContext для каждого JUnit, вы фактически запускаете 300 копий всех ваших прокси и т. Д.

Также помните, что экземпляры Class уникальны для каждого загрузчика классов, а не для всего пространства permgen, поэтому на самом деле могут быть дубликаты в зависимости от того, как настроены ваши прогоны (если это включает развертывание в контейнере или чем-то, хотя это также кажется вряд ли в JUnit :)).

1 голос
/ 14 июня 2011

Я заметил, что вы используете 64-битную JVM. Известно, что они используют вдвое больше реальной памяти на вашем компьютере, потому что для этого требуется вдвое больше места на память.

Если у вас есть тесты JUnit, которые на самом деле загружают контекст Spring (в конце концов, это не Unit), они будут создавать ВСЕ компоненты в вашем appContext. Скорее всего, для этого потребуется более 128 МБ (256 МБ на 64-битной коробке) памяти.

По моему опыту, абсурдно выделять половину гигабайта или больше для большого набора тестов на 64-битной машине. Попробуйте увеличить его до 512 МБ или даже 1 ГБ.

Это параметры, которые я запускаю в одном из тестов моего более крупного проекта с ...

-Xms256m
-Xmx512m
-XX:MaxPermSize=512m
...