JVMシリーズのメモリモデルの詳細な説明

JVMシリーズのメモリモデルの詳細な説明

1. メモリモデルとランタイムデータ領域

この章では、Java 仮想マシンのメモリ モデルについて紹介します。JVM ランタイム データベースは仕様であり、JVM メモリ モデルはこの仕様の実装であると理解できます。

Java 仮想マシンはヒープ領域とメソッド領域にデータを格納することに重点を置いているため、この章ではこれら 2 つの側面についても詳しく説明します。ヒープとメソッド領域は共有メモリですが、Java 仮想マシン スタック、ネイティブ メソッド スタック、およびプログラム カウンターはスレッド専用です。

2. マインドマップと凡例

1 つは非ヒープ領域 (メソッド領域) であり、一般に「永続世代」とも呼ばれます。もう 1 つはヒープ領域で、若い領域と古い領域に分かれています。若い領域は 2 つの部分に分かれており、1 つは Eden 領域、もう 1 つは Survivor 領域 (S0+S1) です。S0 領域は From 領域とも呼ばれ、S1 は To 領域とも呼ばれます。

3. オブジェクトはJVMからスペースを申請する

4. サバイバーゾーンはなぜ必要なのでしょうか?

なぜ生存者エリアが必要なのでしょうか? エデンで十分ではないのですか?

Survivor 領域を設計しないと仮定すると、Eden 領域で MinorGC が実行され、オブジェクトは直接 Old 領域に送られます。このようにすると、Old 領域はすぐにいっぱいになります。Old 領域がいっぱいになると、FullGC が実行されます (Old 領域では MajorGC が実行され、通常は MinorGC が伴います)。FullGC は非常に時間がかかるため、Survivor 領域を設計する目的は、Old 領域に送られるオブジェクトの数を減らすことです。過渡的な Survivor 領域があります。

補足: マイナーGC: 新世代
メジャーGC: 旧世代
フルGC: 新世代 + 旧世代
エデン:S1:S2は8:1:1

5. なぜ 2 つのサバイバー ゾーンが必要なのですか?

2 つの Survivor 領域を必要とする目的は、メモリの断片化を回避することです。なぜそんなことを言うのですか?
Survivor スペースが 1 つだけ設計されていると仮定すると、Eden スペースがいっぱいになると、Minor GC が実行され、Eden スペース内の生き残ったオブジェクトが Survivor スペースに移動されます。次に Eden スペースがいっぱいになると、問題が発生します。Minor GC によって、Eden スペースのオブジェクトが Survivor スペースに強制的に移動され、オブジェクトが占有するメモリが不連続になります。

6. 検証例

ヒープメモリオーバーフロー

lombok.Data をインポートします。
org.springframework.web.bind.annotation.GetMapping をインポートします。
org.springframework.web.bind.annotation.RestController をインポートします。

java.util.ArrayList をインポートします。
java.util.List をインポートします。

@レストコントローラ
パブリッククラスHeapController{

    リスト<Foo> リスト = 新しい ArrayList<Foo>();
    @GetMapping(値 = {"ヒープ"})
    パブリック文字列ヒープテスト() {
        (真)の間{
            リストに追加します(新しいFoo());
        }
    }


    @データ
    クラスFoo {
        文字列 str;
    }
}

インターフェースにアクセスすると、メモリ オーバーフローが発生します。

java.lang.OutOfMemoryError: Java ヒープ スペース

...

パラメータを設定できます: 例: -Xms64M -Xmx512M

メソッド領域のメモリオーバーフロー

asm、maven 構成の使用:

<依存関係>
  <groupId>アセンブラ</groupId>
  <artifactId>アセンブリ</artifactId>
  <バージョン>3.3.1</バージョン>
</依存関係>

コードを記述し、メソッド領域にクラス情報を追加します。コンピュータのパフォーマンスが十分でない場合は、このコードを実行しないでください。コンピュータが再起動する原因になりやすいです。メモリを消費しすぎる場合は、ループの数を減らすこともできます。

org.objectweb.asm.ClassWriter をインポートします。
org.objectweb.asm.MethodVisitor をインポートします。
org.objectweb.asm.Opcodes をインポートします。

java.util.ArrayList をインポートします。
java.util.List をインポートします。

パブリッククラスMyMetaspaceはClassLoaderを拡張します{

  パブリック静的リスト<Class<?>>createClasses() {
    List<Class<?>> classes = new ArrayList<Class<?>>();
    (int i = 0; i < 10000000; ++i) の場合 {
      クラスライター cw = 新しいクラスライター(0);
      cw.visit(Opcodes.V1_1, Opcodes.ACC_PUBLIC, "クラス" + 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(オペコード.RETURN);
      mw.visitMaxs(1, 1);
      mw.visitEnd();
      MyMetaspace テスト = 新しい MyMetaspace();
      バイト[]コード = cw.toByteArray();
      クラス<?> exampleClass = test.defineClass("Class" + i, code, 0,
              コードの長さ);
      クラスを追加します(exampleClass);
    }
    クラスを返します。
  }
}

メソッド領域テストインターフェース:

com.example.jvm.jvmexceptionexample.asm.MyMetaspace をインポートします。
org.springframework.web.bind.annotation.GetMapping をインポートします。
org.springframework.web.bind.annotation.RestController をインポートします。

java.util.ArrayList をインポートします。
java.util.List をインポートします。

@レストコントローラ
パブリッククラスNonHeapController {

    リスト<Class<?>> list = 新しい ArrayList<Class<?>>();

    @GetMapping(値 = {"/noheap"})
    パブリック文字列noheap() {
        (真)の間{
            リストにすべてを追加します(MyMetaspace.createClasses());
        }
    }

}

java.lang.OutOfMemoryError: メタスペース

java.lang.ClassLoader.defineClass1(ネイティブメソッド) ~[na:1.8.5_54]

解決策: Metaspace のサイズを設定します (例: -XX:MetaspaceSize=64M -XX:MaxMetaspaceSize=512M)

Java 仮想マシン スタック

前に学んだように、Java 仮想マシン スタックはスタック フレームの形式で保存されます。1 つのメソッドは 1 つのスタック フレームに対応し、キュー モードでスタックにプッシュされます。したがって、プログラムが Java 仮想マシン スタックに問題を引き起こすかどうかをテストする場合は、再帰メソッドを使用してテストできます。

org.springframework.web.bind.annotation.GetMapping をインポートします。
org.springframework.web.bind.annotation.RestController をインポートします。

@レストコントローラ
パブリッククラスStackController{

    パブリック静的ロングカウント = 0;

    パブリック静的void add(long i) {
        カウント++;
        追加(i);
    }

    @GetMapping(値 = {"スタック"})
    パブリックボイドスタック(){
        追加(1);
    }

}

StackOverflow、スタックオーバーフロー例外:

java.lang.StackOverflowError: null

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

解決策: -Xss256k を設定します: 各スレッドのスタック サイズを設定します。 JDK 5 以降では、各スレッドのスタック サイズは 1M になり、それ以前は、各スレッドのスタック サイズは 256K でした。

以上がJVMシリーズのメモリモデルの詳細説明の内容です。JVMメモリモデルのメモリ構造の詳細については、123WORDPRESS.COMの他の関連記事に注目してください。

以下もご興味があるかもしれません:
  • JavaメモリモデルとJVMランタイムデータ領域の違いの詳細な説明
  • グラフィカル JVM メモリ モデル
  • JVM メモリ モデルの知識ポイントのまとめ
  • JVM メモリ モデルを理解するのに役立つ記事

<<:  Ubuntu 18.04 に mysql5.7.23 をインストールするチュートリアル

>>:  Windows 上で Zookeeper サーバーを構築するチュートリアル

推薦する

JavaScriptでページスクロールアニメーションを実装する

目次レイアウトを作成するCSSスタイルを追加するJavaScript で要素を操作する対象要素を取得...

JavaScript関数の詳細な説明これを指す問題

目次1.関数内のこの方向1. 通常の機能2. コンストラクター3. オブジェクトメソッド4. イベン...

カルーセル例の JavaScript 実装

この記事では、カルーセルの効果を実現するためのJavaScriptの具体的なコードを参考までに共有し...

Linux コマンドラインからファイルを削除する実用的な方法

rm コマンドrm コマンドは、ファイルを削除するときによく使用されるコマンドです。ファイルまたはデ...

CSSをインポートする方法は何ですか?linkと@importの違いは何ですか?選択方法

Taobao のウェブページはインポートを使用していますが、多くのウェブサイトはリンクを使用していま...

MySQL データベースのマスター・スレーブ レプリケーションと読み取り/書き込み分離

目次1. マスタースレーブレプリケーションマスタースレーブレプリケーション3スレッドマスタースレーブ...

Docker+nacos+seata1.3.0 のインストールと使用設定チュートリアル

これに先立ち、1日かけてやってみました。Seataは使い方が簡単で超シンプルですが、インストールや設...

DockerでRedisを使用するための詳細な手順

1. はじめにこの記事では、Docker を使用して Redis を探索する方法を説明します。 Do...

TypeScript をインストール、使用、自動コンパイルする方法に関するチュートリアル

1. TypeScriptの紹介前回の記事ではTypeScriptのインストール、使い方、自動コンパ...

VMware ESXi6.7 の簡単なセットアップ(画像とテキスト付き)

1. VMware vSphere の概要VMware vSphere は、業界をリードする最も信...

タブ切り替え効果を実現するJavaScript

この記事では、タブ切り替え効果を実現するためのJavaScriptの具体的なコードを参考までに紹介し...

Apple 電卓の JS 実装

この記事の例では、Appleの電卓を実装するためのJSの具体的なコードを参考までに共有しています。具...

dubbo での Zookeeper リクエストのタイムアウト問題: mysql8.0.15 に接続する mybatis+spring の構成

ここ2日間Javaを復習するつもりなので、練習にdubboを使ってショッピングモールプロジェクトを書...

CSS でインラインブロック要素間のギャップを削除するいくつかの方法の詳細な説明

最近、モバイルページを制作する際には、レイアウトにインラインブロック要素がよく使われますが、インライ...

docker で PostgreSQL データベースをインストールして永続化する方法

Dockerのインストール手順をスキップする1. postgresqlイメージを取得する docke...