Что, помимо объектов класса, хранится в Perm Gen Space (sun 1.6 VM)?
Я вижу "java.lang.OutOfMemoryError: пространство PermGen" при запуске ~ 300 тестов JUnit и использование контекста w760. С трудом выясняя, что есть PermGen, поскольку:
- в установившемся режиме приложение потребляет около 90 м пространства перм.
- Я пробовал -XX: MaxPermSize = 256 м для модульных тестов - все еще работает
- При включенном
-XX:+TraceClassLoading
и -XX:+TraceClassUnloading
я не вижу дополнительных "загружаемых" событий при выполнении последних 20-30 тестов перед OutOfMemoryError
.
Последнее, по-видимому, предполагает, что что-то помимо объектов класса заполняет PermGen, нет? Если да, то что это может быть? Например, существуют ли обстоятельства, когда класс экземпляры хранятся в PermGen?
Здесь моя информация о VM:
$ 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)
связанные
FWIW, корень моей проблемы, который ускорил этот пост, оказался несколько тривиальным: я предположил, что плагин Maven Surefire наследует параметры VM от MAVEN_OPTS (или экземпляр VM, запущенного mvn), когда он вилки VM - он делает не (boo). Нужно указать те, которые явно используют argLine в конфигурации плагина. НТН.
Ответы
Ответ 1
Иногда злоупотребление String.intern() может вызвать ошибки пространства PermGen, поскольку интерполяционные экземпляры String хранятся в PermGen.
Это может быть то, что вы видите - попробуйте устранить ненужные вызовы String.intern(), чтобы увидеть, разрешает ли это проблема. В общем, я бы не рекомендовал использовать String.intern(), если вы не уверены, что оба из них верны:
- Вы уверены, что будет добавлено только ограниченное количество строк.
- Вам действительно нужны такие строки для совместного использования одного и того же идентификатора объекта (например, если многие экземпляры одних и тех же строк будут потреблять недопустимые объемы памяти или вам нужно полагаться на == для сравнения строк для сложных причин производительности)
Ответ 2
Interned Strings также хранятся в permgen, хотя сотни мегабайт строк sseems маловероятны. Помните, что каждый Spring Bean, для которого вы используете прокси, генерирует новые классы "на лету" во время выполнения, чтобы реализовать интерфейсы, которые вы проксимируете. (Или ваши классы, если вы используете прокси CGLIB и т.д.). Поэтому, если вы создаете "свежий" Spring ApplicationContext для каждого JUnit, вы фактически свергаете 300 копий всех ваших прокси и т.д.
Также помните, что экземпляры класса уникальны для каждого загрузчика классов, но не для всего пространства имен, поэтому на самом деле могут быть дубликаты в зависимости от того, как настроены ваши прогоны (если это связано с развертыванием в контейнере или чем-то еще, хотя это также кажется маловероятно в JUnit:)).
Ответ 3
Я замечаю, что вы используете 64-битную JVM. Известно, что они используют вдвое большую память на вашем компьютере, потому что для распределения требуется вдвое больше пространства памяти.
Если у вас есть тесты JUnit, которые фактически загружают контекст spring (не все Unit), они будут создавать экземпляр ALL beans в вашем appContext. Это, скорее всего, потребует более 128 МБ (256 МБ в 64-битном поле) памяти.
По моему опыту, не абсурдно выделять половину концерта или больше большому набору тестов на 64-битной машине. Попробуйте увеличить его до 512 МБ или даже 1 ГБ.
Это параметры, которыми я запускаю один из моих больших тестовых наборов проектов с...
-Xms256m
-Xmx512m
-XX:MaxPermSize=512m