溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JVM系列之內存模型的示例分析

發布時間:2021-06-10 13:44:50 來源:億速云 閱讀:233 作者:小新 欄目:開發技術

這篇文章主要介紹JVM系列之內存模型的示例分析,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!

1. 內存模型和運行時數據區

這一章學習java虛擬機內存模型(Java Virtual machine menory model),可以這樣理解,jvm運行時數據庫是一種規范,而JVM內存模型是對改規范的實現

JVM系列之內存模型的示例分析

java虛擬機重點存儲數據的是堆和方法區,所以本章節也重點從這兩個方面進行比較詳細描述。堆和方法區是內存共享的,而java虛擬機棧、Native方法棧、程序計數器是線程私有的

JVM系列之內存模型的示例分析

2、思維導圖和圖例

JVM系列之內存模型的示例分析

一個是非堆區(方法區),方法區也一般被稱之為“永久代”。另外一個是堆區,分為young區和old區,young區又分為兩個部分,一個是Eden區,一個是Survivor區(S0+S1),S0區也可以稱之From區,S1也可以稱之為To區

JVM系列之內存模型的示例分析

3、對象向JVM申請空間

JVM系列之內存模型的示例分析

4、為什么需要Survivor區?

為什么需要Survivor區?只有Eden不行嗎?

假設不設計出Survivor區,Eden區進行一次MinorGC,對象就直接被送到Old區,這樣一來Old區很快就被填滿,Old區一滿,就會進行FullGC(Old區會進行MajorGC,一般伴隨著MinorGC),FullGC是很耗時的,所以設計出Survivor區的目的是減少對象被送到Old區,有一個過渡的Survivor區

補充:Minor GC:新生代
Major GC:老年代
Full GC:新生代+老年代
Eden:S1:S2是8:1:1

5、為什么需要兩個Survivor區?

需要兩個Survivor區的目的是為了避免內存碎片化。為什么這么說?
假設只設計出一個Survivor區,一旦Eden區滿了,就會進行Minor GC,Eden區存活的對象就會被移動到Survivor區,等下一次Eden區滿時候,問題就來了,進行MinorGC就將Eden區對象硬放到Survivor區,這樣就導致了對象所占的內存是不連續的

6、例子進行驗證

堆內存溢出

import lombok.Data;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

@RestController
public class HeapController {

    List<Foo> list = new ArrayList<Foo>();
    @GetMapping(value = {"heap"})
    public String heapTest() {
        while (true) {
            list.add(new Foo());
        }
    }


    @Data
    class Foo {
        String str;
    }
}

訪問接口,出現內存溢出;

java.lang.OutOfMemoryError: Java heap space

...

可以設置參數:比如-Xms64M -Xmx512M

方法區內存溢出

使用asm,maven配置:

<dependency>
  <groupId>asm</groupId>
  <artifactId>asm</artifactId>
  <version>3.3.1</version>
</dependency>

編寫代碼,向方法區中添加Class的信息,注意,電腦性能不夠好,不要執行此代碼,很容易,造成電腦重啟,太吃內存,也可以調小循環次數

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import java.util.ArrayList;
import java.util.List;

public class MyMetaspace extends ClassLoader {

  public static List<Class<?>> createClasses() {
    List<Class<?>> classes = new ArrayList<Class<?>>();
    for (int i = 0; i < 10000000; ++i) {
      ClassWriter cw = new ClassWriter(0);
      cw.visit(Opcodes.V1_1, Opcodes.ACC_PUBLIC, "Class" + i, null,
              "java/lang/Object", null);
      MethodVisitor mw = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>",
              "()V", null, null);
      mw.visitVarInsn(Opcodes.ALOAD, 0);
      mw.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object",
              "<init>", "()V");
      mw.visitInsn(Opcodes.RETURN);
      mw.visitMaxs(1, 1);
      mw.visitEnd();
      MyMetaspace test = new MyMetaspace();
      byte[] code = cw.toByteArray();
      Class<?> exampleClass = test.defineClass("Class" + i, code, 0,
              code.length);
      classes.add(exampleClass);
    }
    return classes;
  }
}

方法區測試接口:

import com.example.jvm.jvmexceptionexample.asm.MyMetaspace;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

@RestController
public class NonHeapController {

    List<Class<?>> list = new ArrayList<Class<?>>();

    @GetMapping(value = {"/noheap"})
    public String noheap() {
        while (true) {
            list.addAll(MyMetaspace.createClasses());
        }
    }

}

java.lang.OutOfMemoryError: Metaspace

at java.lang.ClassLoader.defineClass1(Native Method) ~[na:1.8.5_54]

處理方法,設置Metaspace的大小,比如-XX:MetaspaceSize=64M -XX:MaxMetaspaceSize=512M

Java虛擬機棧

在前面學習,java虛擬機棧是通過棧幀方式存儲,一個方法對應一個棧幀,按照隊列模式進棧,所以要測試程序導致java虛擬機棧出現問題,可以通過遞歸方法方式進行測試:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class StackController {

    public static long count = 0;

    public static void add(long i) {
        count ++ ;
        add(i);
    }

    @GetMapping(value = {"stack"})
    public void stack() {
        add(1);
    }

}

StackOverflow,棧溢出異常:

java.lang.StackOverflowError: null

at com.example.jvm.jvmexceptionexample.controller.StackController.add(StackController.java:14) ~[classes/:na]

處理方法,設置-Xss256k:設置每個線程的堆棧大小。JDK 5以后每個線程堆棧大小為1M,以前每個線程堆棧大小為256K

以上是“JVM系列之內存模型的示例分析”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

jvm
AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女