は、バイトコード インタプリタが実行する必要があるバイトコード命令を選択するために使用されます。各スレッドは独立したプログラム カウンタを持ち、スレッドは互いに影響しません。スレッドが Java メソッドを実行している場合、このカウンタは、ネイティブ メソッドを実行している場合、実行中の仮想マシンのバイトコード命令のメモリ アドレスを記録します。カウンタは未定義です。この領域は、JVM 仕様で OOM を持たない唯一の領域です
コンパイラーに認識されているさまざまな基本データ型 (boolean、byte、char、short、int、float、long) を格納します、double)、オブジェクト アプリケーション (参照)。 64 ビットの double と long は 2 スロットを占有します。メモリ空間は、メソッドを開始するときに、このメソッドが割り当てる必要があるメモリ容量を完全に決定します。 -Xss
Exception:
StackOverflowError スタックの深さが仮想よりも大きい仮想マシン スタックが動的に拡張できる場合 (現在のほとんどの Java 仮想マシンは動的に拡張できますが、Java 仮想マシンの仕様では固定長の仮想マシン スタックも許可されています)、十分なメモリを拡張できない場合
単一のスレッドでは、スタック フレームが大きすぎるか、仮想マシンのスタック容量が小さすぎるかに関係なく、メモリを割り当てることができない場合、仮想マシンは 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; } } }
テストが 1 つのスレッドに限定されていない場合スレッド、連続経由 スレッドの作成方法により、メモリ オーバーフロー例外が発生する可能性があります。ただし、この方法で生成されるメモリ オーバーフロー例外は、占有領域が十分に大きいかどうかとは関係がありません。正確に言えば、この場合、各スレッドのスタックに割り当てられるメモリが大きいほど、メモリ オーバーフロー例外が生成されやすくなります。 。
オペレーティング システムによって各プロセスに割り当てられるメモリは制限されているため、たとえば、32 ビット ウィンドウは 2GB に制限されます。このテストは、多数のスレッドを作成することによって行われます。各スレッドがスタック メモリを占有し、大量のメモリを割り当てるため、システムに十分なメモリが不足します。自動的に展開することはできません
/** * 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(); } }
ネイティブ メソッド スタック
例外:
StackOverflowError スタックの深さ仮想マシンで許容される深さよりも大きいです
OOM
Javaヒープ
例外: ヒープを拡張できない場合は
1.OOM
/** * 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()); } } }
メソッド領域
1.6 以前では、ランタイム定数はメソッド領域の一部です (String.intern() は定数プールに動的に追加されます) -XX:MaxPermSize によってサイズが制御されます。 JDK1.7 以降のバージョンでは、これは Java ヒープ内で開かれたメモリの一部です
例外状況:
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 { } }
ダイレクト メモリ (仮想マシンの実行中にデータ領域の一部ではありません)
例外:
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); } } }
以上がJVM の各領域の目的の詳細な説明と、潜在的な例外のコード例の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。