Java仮想マシン2 - ノートの深い理解

免責事項:この記事は、ブロガーオリジナル記事です転載を歓迎します。https://blog.csdn.net/guo_xl/article/details/91358266

VMスタックとネイティブメソッドスタックオーバーフロー

一般的なネイティブメソッドはめったにスタックオーバーフローしていない、スタックは、より一般的な仮想マシンをオーバーフロー

  • コード1
//VM args :-Xss128k  指定帧栈的容量
	public void hello() {
		hello();
	}

	public static void main(String[] args) {
		StackOverFlow stackOverFlow = new StackOverFlow();
		//线程栈里的VMstack是有限的,也就是容纳的栈帧数是有限的
		//栈帧数不断的增加会最后导致stack over flow,叫栈溢出
		stackOverFlow.hello();
	}

エラー

Exception in thread "main" java.lang.StackOverflowError
	at rechard.learn.jvm.StackOverFlow.hello(StackOverFlow.java:8)
	at rechard.learn.jvm.StackOverFlow.hello(StackOverFlow.java:8)
  • コード2
public static void main(String[]args){
		while(true){
			//jvm里的内存是有限的,
			//线程创建出来,线程栈是需要一定的内存的
			//一直创建线程,并且线程一直在运行,也就是GC不会回收这些线程,
			//迟早会出现内存溢出,出现oom
			//解决方法:
			//1.控制线程数,通过线程池控制。 Excutors.newxxxx
			//2.-xss:减小线程栈的内存分配以达到能创建更多的线程数
			new Thread(new Runnable(){
				public void run() {
					while(true){
						try {
							Thread.sleep(10);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
				}
				
			}).start();
		}
	}

エラー

Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
	at java.lang.Thread.start0(Native Method)
	at java.lang.Thread.start(Thread.java:717)
	at rechard.learn.jvm.StackoutOfMemory.main(StackoutOfMemory.java:25)

ヒープメモリの不足

//vm args:-Xmx20M -Xms20M -verbose:gc
//堆里不断的创建对象,最后会造成堆里的内存空间不足,而导致oom
	public static void main(String []args){
		List cases = new ArrayList();
	    while(true){	    	
	        cases.add(new Object());
	    }
	}

次のように考えます

[GC (Allocation Failure)  5572K->2988K(19968K), 0.0081114 secs]
[GC (Allocation Failure)  8620K->7087K(19968K), 0.0150993 secs]
[GC (Allocation Failure)  12719K->12733K(19968K), 0.0168034 secs]
[Full GC (Ergonomics)  12733K->10732K(19968K), 0.2536876 secs]
[Full GC (Ergonomics)  16364K->14254K(19968K), 0.1547094 secs]
[Full GC (Ergonomics)  16696K->16599K(19968K), 0.2127199 secs]
[Full GC (Allocation Failure) Exception in thread "main"  16599K->16580K(19968K), 0.1892626 secs]
java.lang.OutOfMemoryError: Java heap space

メソッドのオーバーフロー

ランタイム定数プールが地区法の一部であり、実行時定数プールは、ヒープに1.8に配置されています

public static void main(String[] args) {  
        List<String> list = new ArrayList<String>();  
        int i = 0;  
        while(true){  
            list.add(String.valueOf(i++).intern());
            //System.out.println(i);
        }
    }  

エラー

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.lang.Integer.toString(Integer.java:401)
	at java.lang.String.valueOf(String.java:3099)
	at rechard.learn.jvm.StringInternOOM.main(StringInternOOM.java:12)

プラス-verbose:gc -Xmx20Mの後

[Full GC (Ergonomics)  19455K->19455K(19968K), 0.1024099 secs]
[Full GC (Allocation Failure)  19455K->19455K(19968K), 0.1182977 secs]
[Full GC (Ergonomics) Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

可視ヒープ最終的19455K-> 19455K(19968K)は、ヒープ内のその定数プールを示します

奇妙なことは、上記のコードを手放すされSystem.out.println(i);、エラーとなっています

Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
	at java.lang.Integer.toString(Integer.java:401)
	at java.lang.String.valueOf(String.java:3099)
	at java.io.PrintStream.print(PrintStream.java:597)
	at java.io.PrintStream.println(PrintStream.java:736)
	at rechard.learn.jvm.StringInternOOM.main(StringInternOOM.java:13)

時間の98%以上は、GCのために使用され、2%未満のヒープメモリのこの例外をスロー回復します。あなたが使用することができ
-XXを:このチェックを無効に-UseGCOverheadLimitなります
[全GC(人間工学)例外でスレッド「メイン」java.lang.OutOfMemoryErrorを:Javaヒープスペース

String.intern

インターンメソッドが呼び出されると、プールが既に含まれている場合、
によって決定されるように、この{@code文字列}オブジェクトに等しい*列
*、その後、プールからの文字列は、{@link #equals(オブジェクト)}メソッドである
*返さを。そうでない場合は、この{@code文字列}オブジェクトがに追加された
*プールこの{@code文字列}オブジェクトへの参照が返されます。

公式の説明は:定数プールはすでに文字列オブジェクトが含まれている場合、そのオブジェクトを直接返され、そうでない場合は、定数プールにこのオブジェクトを追加してから戻ります

 public static void main(String[] args) {
        String b=new String ("A").intern();//创建后返回
        String a="A";
        String c=new String("A");
        System.out.println(a==b); 
        System.out.println(a==c);

        String d=new String ("B");
        String d1=d.intern();
        System.out.println(d==d1);

        System.out.println(d1=="B");
    }

業績

true
false
false
true

javap -v StringDemo.class分析することにより

constant pool:
   #1 = Methodref          #10.#34        // java/lang/Object."<init>":()V
   #2 = Class              #35            // java/lang/String
   #3 = String             #36            // A
  。。。

Code:
      stack=3, locals=6, args_size=1
         0: new           #2                  // class java/lang/String  new 一个引用类型并压入栈顶
         3: dup   //对栈顶复制一份并压入栈顶
         4: ldc           #3                  // String A 将int ,float或String  类型从本地变量表里的压栈,这里是#3,即对应constant pool里的#3,即将A 入栈
         6: invokespecial #4                  // Method java/lang/String."<init>":(Ljava/lang/String;)V // 调用<init>
         9: invokevirtual #5                  // Method java/lang/String.intern:()Ljava/lang/String;  //调用intern
        12: astore_1                            //  9里执行完其实是将常量池里的"A"的引用压栈,astore_1  是将栈顶的引用存入到第2个本地变量中,本地变量表是虚拟机栈的一部分,对应上面的locals=6是说本地变量表 有6个,对应下面的 LocalVariableTable 里的13     100     1     b   Ljava/lang/String; 即将"A" 付给了b
        13: ldc           #3                  // String A  //同上面4的注释
        15: astore_2      // 对应下面的LocalVariableTable里的第3行,即将"A"付给了a
        。。。
     LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0     113     0  args   [Ljava/lang/String;
           13     100     1     b   Ljava/lang/String;
           16      97     2     a   Ljava/lang/String;


おすすめ

転載: blog.csdn.net/guo_xl/article/details/91358266