Java использует гораздо больше памяти, чем выделено с помощью -Xmx

У меня есть проект, который я пишу (на Java) для класса, где профессор говорит, что нам не разрешено использовать более 200 м Я ограничиваю память стека до 50 м (просто для того, чтобы быть абсолютно уверенным) с -Xmx50m, но, согласно началу, он все еще использует 300 м

Я попытался запустить Eclipse Memory Analyzer и он сообщает только 26m

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

Программа однопоточная. Кто-нибудь знает какие-либо другие места, в которых я мог бы уменьшить использование памяти? Кроме того, как я могу проверить/ограничить, сколько памяти использует стек?

UPDATE: теперь я использую следующие параметры JVM без эффекта (по-прежнему около 300 м): -Xss104k -Xms40m -Xmx40m -XX:MaxPermSize=1k

Другое ОБНОВЛЕНИЕ: На самом деле, если я позволю ему немного подождать (со всеми этими параметрами) примерно в половине случаев, когда он внезапно опустится до 150 м через 4 или 5 секунд (другая половина его не исчезнет). Что действительно странно, так это то, что моя программа не имеет стохастичности (и, как я сказал, это однопоточная), поэтому нет причин, по которым она должна вести себя по-разному на разных прогонах

Может ли это иметь какое-то отношение к JVM, который я использую?

java version "1.6.0_27"
OpenJDK Runtime Environment (IcedTea6 1.12.3) (6b27-1.12.3-0ubuntu1~10.04)
OpenJDK 64-Bit Server VM (build 20.0-b12, mixed mode)

Согласно java -h, JVM по умолчанию - это -сервер. Я попробовал добавить -cacao и теперь (со всеми остальными вариантами) - всего 59 м. Поэтому я полагаю, что это решает мою проблему. Может ли кто-нибудь объяснить, почему это было необходимо? Кроме того, есть ли какие-то недостатки, о которых я должен знать?

Еще одно обновление: cocoa действительно очень медленное по сравнению с сервером. Это ужасный вариант

Ответ 1

Верхняя команда отражает общий объем памяти, используемой приложением Java. Это включает в себя, среди прочего:

  • Основные издержки памяти самого JVM
  • пустое пространство (ограниченное -Xmx)
  • Постоянное пространство генерации (-XX: MaxPermSize - не стандартно во всех JVM)
  • пространство стека потоков (-Xss за стек), которое может значительно увеличиться в зависимости от количества потоков
  • Пространство, используемое встроенными выделениями (с использованием класса ByteBufer или JNI)

Ответ 2

С -Xmx вы настраиваете размер кучи. Для настройки размера стека используйте параметр -Xss. Сумма этих двух параметров должна быть примерно той, что вы хотите:

-Xmx150m -Xss50m

например.

Кроме того, имеется параметр -XX:MaxPermSize, который управляет. Этот параметр для -client имеет значение по умолчанию 32 МБ и для -server 64 МБ. В соответствии с вашей конфигурацией вычислите его также. Пространство PermGen:

Постоянное поколение используется для отображения отражающей самой виртуальной машины, такой как объекты класса и объекты метода.

Таким образом, в основном он хранит внутренние данные JVM, такие как определения классов и встроенные строки.

В конце я должен сказать, что есть одна часть, которую вы не можете контролировать, то есть память, используемая собственным процессом Java. Java - это программа, как и любая другая, поэтому она также использует память. Если вы просматриваете использование памяти в диспетчере задач, вы также увидите эту память вместе с потреблением вашей программной памяти.

Ответ 3

Max memory = [-Xmx] + [-XX:MaxPermSize] + number_of_threads * [-Xss]

здесь максимальная память кучи как -Xmx, минимальная память кучи как -Xms, стек памяти как -Xss и -XX maxPermSize

Следующий пример иллюстрирует эту ситуацию. Я запустил свой tomcat со следующими параметрами запуска:

-Xmx168m -Xms168m -XX:PermSize=32m -XX:MaxPermSize=32m -Xss1m

Ответ 4

Вы пытались использовать JVisualVM?

http://docs.oracle.com/javase/6/docs/technotes/tools/share/jvisualvm.html

Я часто находил, что это помогает мне отслеживать этот материал. Он покажет вам, сколько из каждого типа памяти используется, даже позволяя вам разбудить и узнать, что.

Ответ 5

Важно отметить, что "используемая общая память" (RSS на земле Linux) включает кучу JDK (+ другие области JDK), а также выделенную "родную память".

Например, эти люди обнаружили, что выделение слишком большого количества jaxbcontexts (которые связаны с родной памятью) между GC может привести к тому, что он будет использовать много дополнительной ОЗУ. Другой распространенный, по-видимому, ZipInflater, если вы не вызываете его близко (или GZipStream и т.д.)

http://sleeplessinslc.blogspot.com/2014/08/jvm-native-memory-leak.html

Его окончательное решение об обходе/исправить было либо с GC "чаще" (с помощью сборщика мусора GC1, либо указав меньшую [иронически] -Xmx-настройку), либо путем кэширования объектов JaxBContext (поскольку у них нет закрытого метода, поэтому вы можете 't контролировать утечку).

Также обратите внимание, что иногда вы можете найти виновников памяти, просто изучив jstack: http://javaeesupportpatterns.blogspot.com/2011/09/jaxbcontext-performance-problem-case.html

Также иногда возможно "пропустить" закрытие, например, GZipStreams случайно http://kohsuke.org/2011/11/03/quiz-time-memory-leak-in-java