Куча Java используется для хранения экземпляров объектов. Поэтому, если мы непрерывно создаем объекты и обеспечим, чтобы между корнем GC и созданным объектом существует доступный путь, чтобы избежать собранного мусора объекта, то, когда будет создано слишком много объектов, он приведет к недостаточной памяти кучи, что поднимет исключение OutoFmemoryError.
/** * @author xiongyongshun * vm args: java -xms10m -xmx10m -xx:+heapdumponoutofmemoryerror */public class outofmemoryerrortest {public static void main (string [] args) {listeger> list = new ArrayList <> (); int i = 0; while (true) {list.add (i ++); }}}Выше приведено код, который поднимает исключение OutofmemoryError. Мы видим, что он предотвращает, как объект собирается, постоянно создавая и сохраняя объект в списке. Поэтому, когда слишком много объектов, память кучи переполнится.
Через java -xms10m -xmx10m -xx:+heapdumponoutofmemororror, мы устанавливаем память кучи на 10 мегабайт и используем параметр -xx:+Heapdumponoutofmemororror, чтобы сделать JVM распечатать текущий снимок памяти, когда возникает исключение OutofmoryError.
После составления и запуска вышеуказанного кода будет следующая вывод:
>>> java -xms10m -xmx10m -xx:+heapdumponoutofmemoryerror com.test.outofmemoryerrortest 16-10-02 23: 35java.lang.outofmemoryerr: gava huep sacdepuping heap in java_pid1810.hprof ... heal -файл, созданный. 0,125 секунды] Исключение в Thread "Main" java.lang.outofmemoryError: Java Heap Space на java.util.arrays.copyof (arrays.java:3210) на java.util.arrays.copyof (arrays.java:3181) в java.util.raylist.graylist.java:3181) в java.util.raylist.graylist.java:3181). java.util.arraylist.ensureexplicitcapacity (arraylist.java:235) на java.util.arraylist.ensurecapacityinternal (arraylist.java:227) на java.util.arraylist.add (Arraylist.java:458) в com.test.outofmemoryerrortest.main (OutofmemoryErrortest.java:15)
Java StackoverflowerRor
Мы знаем, что в области данных JVM есть область памяти, называемая стеком виртуальных машин. Функция этой области: каждый метод создаст кадр стека, когда он будет выполнен, который используется для хранения информации, такой как локальные переменные таблицы, стеки операндов, выходы методов и т. Д.
Поэтому мы можем создать бесконечно рекурсивный рекурсивный вызов. Когда рекурсивная глубина слишком большая, пространство стека будет истощено, что приведет к исключению StackoverFlowerRor.
Вот конкретный код:
/** * @author xiongyongshun * vm args: java -xss64k */public class outofmemoryerrortest {public static void main (string [] args) {StackoutofMemoryError (1); } public static void stackoutOfMemoryError (int devil) {devil ++; Stackoutofmemoryerror (глубина); }}После компиляции и запуска вышеуказанного кода будет выведена следующая информация об исключении:
Исключение в потоке "Main" java.lang.stackoverflowerror в com.test.outofmemoryerrortest.stackoutofmemoryerror (Outofmemoryerrortest.java:27)
Переполнение памяти в области метода
Обратите внимание, что, поскольку JDK8 удалил постоянное поколение и заменил его Metaspace, в JDK8, ни один из следующих двух примеров не приведет к Java.lang.outofmemoryerror: исключение пространства перми.
Постоянные переполнения пула во время выполнения
В Java 1.6 и предыдущих версиях Hotspot JVM существует концепция постоянного поколения, то есть механизм сбора генерации GC распространяется на область метода. В области метода часть памяти используется для хранения постоянных бассейнов. Следовательно, если в коде слишком много констант, память постоянного пула будет исчерпана, что приведет к переполнению памяти. Так как добавить большое количество констант в постоянный бассейн? В настоящее время вам нужно полагаться на метод string.intern (). Функция метода string.intern () состоит в том, что значение этой строки уже существует в постоянном пуле, этот метод возвращает ссылку на соответствующую строку в постоянном пуле; В противном случае добавьте значение, содержащееся в этой строке в постоянный пул, и верните ссылку на этот объект строки. В JDK 1.6 и предыдущих версиях постоянный пул выделяется в постоянном поколении. Поэтому мы можем косвенно ограничить размер постоянного пула, установив параметры «-xx: permsize» и «-xx: maxpermsize».
Обратите внимание, что распределение памяти метода string.intern (), упомянутое выше, и постоянный пул предназначен только для JDK 1.6 и предыдущих версий. В JDK 1,7 или выше макет памяти немного отличается, потому что концепция постоянной генерации удаляется.
Ниже приведен пример кода для реализации переполнения памяти постоянных пулов:
/** * @author xiongyongshun * vm args: -xx: permsize = 10m -xx: maxpermsize = 10m */public class rontimeconstantpooloomtest {public static void main (string [] args) {list <string> list = new ArrayList <string> (); int i = 0; while (true) {list.add (string.valueof (i ++). inger ()); }}}Мы видим, что в этом примере он точно использует метод string.intern () для добавления большого количества констант строк в постоянный пул, который приводит к переполнению памяти постоянного пула.
Мы скомпилируем и запускаем приведенный выше код через JDK1.6, и будет следующим выводом:
Исключение в потоке "Main" java.lang.outofmemoryerror: Pertgen Space at java.lang.string.intern (нативный метод) на com.test.runtimeconstantpooloomtest.main (runtimeconstantpooloomtest.java:16)
Следует отметить, что если приведенный выше код будет составлен и запускается через JDK1.8, будет следующее предупреждение, и не будет сгенерировано исключение:
>>> java -xx: permsize = 10m -xx: maxpermsize = 10m com.test.runtimeconstantpooloomtest 16-10-03 0: 23 Java Hotsopot (TM) 64-битный VM Warning: игнорирование опциона Permazize = 10M; Поддержка была удалена в 8.0 Java Hotspot (TM) 64-разрядной VM Warning: игнорирование опции MaxPermsize = 10M; Поддержка была удалена в 8.0
Переполнение памяти в области метода
Функция области метода состоит в том, чтобы хранить соответствующую информацию о классе, такую как имена классов, модификаторы доступа к классу, описания поля, описания методов и т. Д. Поэтому, если область метода слишком мала и слишком много классов загружается, переполнение памяти области метода.
// vm args: -xx: permsize = 10m -xx: maxpermsize = 10mpublic class methodAreaoomtest {public static void main (string [] args) {while (true) {Enhancer Enhancer = new Enhancer (); Enhancer.setSuperClass (methodAreaOoomtest.class); Enhancer.SetUseCache (false); Enhancer.SetCallback (New MethodInterceptor () {public Object Intercept (объект O, метод метода, объект [] объекты, методпрокси -методпрокси) бросает throwable {return methodproxy.invokesuper (o, objects);}}); Enhancer.create (); }}}В приведенном выше коде мы используем CGLIB для динамического генерации большого количества классов. В JDK6 запуск вышеуказанного кода будет генерировать OutofmemoryError: Impgen Space Exception:
/System/library/frameworks/javavm.framework/versions/1.6/home/bin/java-jar -xx: permsize = 10m -xx: maxpermsize = 10m target/test-1.0-snapshot.jar
Результат вывода заключается в следующем:
Вызвано: java.lang.outofmemoryerror: permgen space at java.lang.classloader.defineclass1 (нативный метод) на java.lang.classloader.defineclasscond (classloader.java:637) на java.lang.classload.defineclass (classulder.java.621) ...
Metaspace память переполнен
В разделе переполнения памяти памяти в области переполнения памяти в области метода мы упомянули, что JDK8 не имеет концепции постоянного поколения, поэтому эти два примера не достигли ожидаемого эффекта в соответствии с JDK8. Итак, в JDK8 есть ли какие -либо ошибки, такие как переполнение памяти в области метода? Конечно, некоторые. В JDK8 область Metaspace используется для хранения информации, связанной с классом, поэтому, когда Metaspace недостаточна, Java.lang.outofmemoryerror: Metaspace Exception будет брошено.
Давайте возьмем пример, упомянутый выше в качестве примера:
// vm args: -xx: maxmetaspacesize = 10mpublic class methodareaoomtest {public static void main (string [] args) {while (true) {Enhancer Enhancer = new Enhancer (); Enhancer.setSuperClass (methodAreaOoomtest.class); Enhancer.SetUseCache (false); Enhancer.SetCallback (New MethodInterceptor () {public Object Intercept (объект O, метод метода, объект [] объекты, методпрокси -методпрокси) бросает throwable {return methodproxy.invokesuper (o, objects);}}); Enhancer.create (); }}}Кодовая часть этого примера не была изменена. Единственное отличие состоит в том, что нам нужно использовать JDK8 для запуска этого кода, и установить параметр -xx: maxmetaspacesize = 10m. Этот параметр сообщает JVM, что максимальный размер Metaspace составляет 10 м.
Затем мы используем JDK8 для компиляции и запуска этого примера, и вынимаем следующее исключение:
>>> java -jar -xx: maxmetaspacesize = 10m target/test -1.0 -snapshot.jarexception в Thread "main" java.lang.outofmemoryerror: metaspace at net.sf.cglib.core.abstractclassgenerator.generhat net.sf.cglib.proxy.enhancer.generate (enhancer.java:492) на net.sf.cglib.core.abstractclassgenerator $ classloaderdata.get (AbstractClassGenerator.java:114) net.sf.cglib.core.abstractclassgenerator.create (AbstractClassGenerator.java:291) на net.sf.cglib.proxy.enhancer.createhelper (Enhancer.java:480) на net.sf.clib.proxy.enhancer.create (enhance.jjavav.javav.javav.javav.javavav.javav.javav.javavav.javav.javavav.javavav.javavavav.creat.create. com.test.methodareaoomtest.main (methodareaoomtest.java:22)
Суммировать
Выше приведено все об общих исключениях переполнения памяти и примеров кода в этой статье, я надеюсь, что это будет полезно для всех. Заинтересованные друзья могут продолжать ссылаться на другие связанные темы на этом сайте. Если есть какие -либо недостатки, пожалуйста, оставьте сообщение, чтобы указать это. Спасибо, друзья, за вашу поддержку на этом сайте!