Heim  >  Artikel  >  Java  >  Detaillierte Erläuterung des Zwecks jedes Bereichs der JVM und Codebeispiele für mögliche Ausnahmen

Detaillierte Erläuterung des Zwecks jedes Bereichs der JVM und Codebeispiele für mögliche Ausnahmen

黄舟
黄舟Original
2017-03-20 10:56:191983Durchsuche

Programmzähler

wird für den Bytecode-Interpreter verwendet, um die Bytecode-Anweisungen auszuwählen, die ausgeführt werden müssen. Jeder Thread verfügt über einen unabhängigen Programmzähler und die Threads beeinflussen sich nicht gegenseitig. Wenn der Thread eine Java-Methode ausführt, zeichnet dieser Zähler die Speicheradresse der ausgeführten Bytecode-Anweisung der virtuellen Maschine auf; wenn er eine native Methode ausführt. Der Zähler ist undefiniert. Dieser Bereich ist der einzige Bereich in der JVM-Spezifikation, in dem OOM nicht existiert.

Virtual-Machine-Stapel (lokaler Variablenraum)

speichert verschiedene grundlegende Datentypen, die dem Compiler bekannt sind (Boolescher Wert, Byte, Zeichen). , short, int, float, long, double), Objektanwendung (Referenz). 64-Bit Double und Long belegen 2 Steckplätze. Der Speicherplatz kann während der Kompilierung bestimmt werden. Der von dieser Methode zuzuweisende lokale Variablenbereich wird vollständig durch -Xss bestimmt.

Ausnahme:

StackOverflowError Die Stapeltiefe ist größer als die von der virtuellen Maschine zulässige Tiefe

OOM Wenn der Stapel der virtuellen Maschine dynamisch erweitert werden kann (die meisten aktuellen Java Virtual Machines können dynamisch erweitert werden, die Java Virtual Machine-Spezifikation erlaubt dies jedoch auch). Stapel virtueller Maschinen mit fester Länge), wenn die Erweiterung nicht genügend Speicher anwenden kann

In einem einzelnen Thread, unabhängig davon, ob der Stapelrahmen zu groß oder die Stapelkapazität der virtuellen Maschine zu klein ist, kann der Speicher nicht zugewiesen werden , die virtuelle Maschine wirft Sie sind alle StackOverflowError

/**
* VM Args:-Xss128k
* 
* stack length:2402 Exception in thread "main" java.lang.StackOverflowError
*/
public class JavaVMStackSOF {

private int stackLength = 1;

public void stackLeak() {
    stackLength++;
    stackLeak();
}

public static void main(String[] args) throws Throwable {
    JavaVMStackSOF oom = new JavaVMStackSOF();
    try {
        oom.stackLeak();
    } catch (Throwable e) {
        System.out.println("stack length:" + oom.stackLength);
        throw e;
    }
}
}

Wenn der Test nicht auf einen einzelnen Thread beschränkt ist, können durch kontinuierliches Einrichten von Threads Speicherüberlaufausnahmen generiert werden. Die auf diese Weise generierte Speicherüberlaufausnahme hängt jedoch nicht davon ab, ob der belegte Speicherplatz groß genug ist. In diesem Fall ist es umso einfacher, eine Speicherüberlaufausnahme zu generieren, je größer der für den Stapel jedes Threads zugewiesene Speicher ist . .

Da der vom Betriebssystem jedem Prozess zugewiesene Speicher begrenzt ist, ist beispielsweise ein 32-Bit-Fenster auf 2 GB begrenzt. Dieser Test wird durch die Erstellung einer großen Anzahl von Threads durchgeführt. Jeder Thread belegt Stapelspeicher und weist eine große Menge Speicher zu, was dazu führt, dass das System nicht über genügend Speicher verfügt. Damit es nicht automatisch erweitert werden kann

/**
 * VM Args:-Xss2M (这时候不妨设大些)
 *
 * java.lang.OutOfMemoryError:unable to create new native thread
 */
public class JavaVMStackOOM {

       private void dontStop() {
              while (true) {
              }
       }

       public void stackLeakByThread() {
              while (true) {
                     Thread thread = new Thread(new Runnable() {
                            @Override
                            public void run() {
                                   dontStop();
                            }
                     });
                     thread.start();
              }
       }

       public static void main(String[] args) throws Throwable {
              JavaVMStackOOM oom = new JavaVMStackOOM();
              oom.stackLeakByThread();
       }
}

Der lokale Methodenstapel

ähnelt dem Stapel der virtuellen Maschine, mit der Ausnahme, dass einer die virtuelle Maschine ist, die Java-Methoden ausführt, und der andere die native Ausführung Methoden

Ausnahmestatus:

StackOverflowError Die Stapeltiefe ist größer als die von der virtuellen Maschine zulässige Tiefe

OOM

Java-Heap

Ein von Threads gemeinsam genutzter Speicherbereich. Aus Sicht des Speicherrecyclings scheint es grundsätzlich so zu sein, dass der Generationssammlungsalgorithmus verwendet wird, sodass er in die neue und die alte Generation unterteilt wird. Genauer gesagt kann es in Eden-Raum, Vom Überlebensraum, Zum Überlebensraum usw. unterteilt werden. -Xmx -Xms steuert die Heap-Speicherplatzgröße

Ausnahme:

1.OOM Wenn der Heap nicht erweitert werden kann

/**
 * VM Args:-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
 * 
 * java.lang.OutOfMemoryError: Java heap space
 */
public class HeapOOM {

    static class OOMObject {
    }

    public static void main(String[] args) {
        List<OOMObject> list = new ArrayList<OOMObject>();

        while (true) {
            list.add(new OOMObject());
        }
    }
}

Methodenbereich

Geteilt zwischen Threads. Speichert Daten wie Klasseninformationen, Konstanten, statische Variablen, vom Instant-Editor kompilierter Code usw., die von der virtuellen Maschine geladen wurden. Dies kann als unsterbliche Generation in der virtuellen HotSpot-Maschine bezeichnet werden.

Laufzeitkonstanten sind Teil des Methodenbereichs in 1.6 und davor (String.intern() fügt den Konstantenpool dynamisch hinzu) -XX:MaxPermSize steuert die Größe. In JDK1.7 und späteren Versionen wird ein Teil des Speichers im Java-Heap geöffnet

Ausnahmesituation:

OOM

/**
* 需要在JDK1.6上才能复现,JDK1.7及之后版本的JVM已经将运行时常量池从方法区中移了出来,在Java 堆(Heap)中开辟了一块区域存放运行时常量池。
* 在JDK1.7上运行的效果则会一直执行,直到堆内存使用完毕
* VM Args:-XX:PermSize=10M -XX:MaxPermSize=10M 
*
* java.lang.OutOfMemoryError:PermGen space
*/
public class RuntimeConstantPoolOOM {

public static void main(String[] args) {
    // 使用List保持着常量池引用,避免Full GC回收常量池行为
    List<String> list = new ArrayList<String>();
    // 10MB的PermSize在integer范围内足够产生OOM了
    int i = 0;
    while (true) {
        list.add(String.valueOf(i++).intern());
    }
}
}
/**
* VM Args: -XX:PermSize=10M -XX:MaxPermSize=10M
* java.lang.OutOfMemoryError:PermGen space
* 一直创建动态类
*/
public class JavaMethodAreaOOM {

public static void main(String[] args) {
    while (true) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(OOMObject.class);
        enhancer.setUseCache(false);
        enhancer.setCallback(new MethodInterceptor() {
            public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                return proxy.invokeSuper(obj, args);
            }
        });
        enhancer.create();
    }
}

static class OOMObject {

}
}

Direkter Speicher (nicht (Teil eines Teils des Datenbereichs, wenn die virtuelle Maschine ausgeführt wird)

NIO kann die native Funktionsbibliothek verwenden, um externen Speicher direkt zuzuweisen, und dann über das im Java-Paar gespeicherte DirectByteBuffer-Objekt als Referenz darauf arbeiten Erinnerung. Begrenzt durch den physischen Speicher der Maschine, kann er über -XX:MaxDirectMemorySize angegeben werden. Wenn nicht angegeben, ist der Standardwert derselbe wie das Java-Heap-Maximum (-Xmx)

Ausnahme:

1 .OOM

/**
 * VM Args:-Xmx20M -XX:MaxDirectMemorySize=10M
 * 
 * java.lang.OutOfMemoryError
 */
public class DirectMemoryOOM {

    private static final int _1MB = 1024 * 1024;

    public static void main(String[] args) throws Exception {
        Field unsafeField = Unsafe.class.getDeclaredFields()[0];
        unsafeField.setAccessible(true);
        Unsafe unsafe = (Unsafe) unsafeField.get(null);
        while (true) {
            unsafe.allocateMemory(_1MB);
        }
    }
}

Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung des Zwecks jedes Bereichs der JVM und Codebeispiele für mögliche Ausnahmen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn