JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))

文章目录

  • 前言
  • 零、问题引入
  • 一、java Runtime Data Area
    • 0、概述
    • 1、Program Counter 程序计数器(线程私有)
    • 2、JVM stacks(重点)(线程私有)
    • 3、Native Method Stacks本地方法栈(线程私有)
    • 4、Direct Memory
    • 5、Method Area 方法区(重点)(线程公有)
      • a、MA
      • b、常量池
      • c、JDK1.6、JDK1.7、JDK1.8 内存模型演变
    • 6、Run-Time Constant Pool(属于MA)
    • 7、Heap 堆(线程共有)
    • 8、总体图
  • 二、java stack 中的 ==栈针Frame==
    • 1、栈针的四部分
    • 2、Local Variable Table 局部变量表
      • a、问题引入的代码
      • b、查看字节码中的本地变量表
    • 3、Operand Stack(解释i++和++i的问题)
      • a、解释指令集:i++
      • b、解释指令集:++i
  • 三、栈的执行流程
    • 1、案例 1_sipush 指令
      • a、代码
      • b、字节码指令集
      • c、指令解说
    • 2、案例 2_局部变量表中的this
      • a、代码
      • b、字节码指令集
      • c、指令解说
    • 3、案例 3_加法指令_iadd
      • a、代码
      • b、字节码指令集
      • c、指令解说
    • 4、案例 4_创建对象指令
      • a、代码
      • b、字节码 指令集
      • c、指令解说
    • 5、案例 5
      • a、案例5_1
        • i、代码
        • ii、字节码指令集
        • iii、指令解说
      • b、案例5_2
        • i、代码
        • ii、字节码指令集
        • iii、指令解说
    • 6、案例 6 (递归指令集解说)
      • a、代码
      • b、字节码指令集:
      • c、指令解说
  • 四、常用指令
    • 1、常用命令
    • 2、invoke-共5个指令
    • 3、JDK1.8之前的一个BUG

前言

  1. 前边的 JVM知识体系学习 1-4讲的是 class loader (类加载)类对象等知识。那这里讲的就是 类加载之后运行时 的数据区域,也就是 java 运行时数据区(java runtime data area),如下图所示:
    JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第1张图片
  2. JVM 文档 是 JDK 13版本
  3. 本博客记录了JVM运行时区域的内容
    • 线程私有:JVM栈、本地方法栈、PC(程序计数器)
    • 线程公有:Java 堆(在第六节里详细讲解)、方法区(7之前永久代实现,7之后元空间实现)
  4. 还记录了 栈中指令涉及局部变量表、操作数栈的实现过程。举了多个例子。

零、问题引入

很简单的小程序,为什么执行第六行代码是8,执行第7行代码是9呢。引入问题,后面解答。

看了答案之后的思维发散:说明 i++ 还是 ++i,都不是原子操作,在字节码层面是由三个指令的,(题外话,也就是JVM知识体系三中的会可能发生指令重排的情况。)。

package com.mashibing.jvm.c4_RuntimeDataAreaAndInstructionSet;

public class TestIPulsPlus {
    public static void main(String[] args) {
        int i = 8;
        i = i++;
//        i = ++i;
        System.out.println(i);
    }
}

一、java Runtime Data Area

0、概述

  1. 数据运行时内存包含如下
    DM 是JDK1.4之后出现的,为NIO部分。
    JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第2张图片
  2. 对应的文档在哪呢
    • https://docs.oracle.com/javase/specs/index.html
      JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第3张图片
    • 上面是java language,下面是 JVM ,点击PDF即可。
    • 位置如下:
      JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第4张图片

1、Program Counter 程序计数器(线程私有)

存放指令位置
虚拟机的运行,类似于这样的循环:
while( not end ) {
取PC中的位置,找到对应位置的指令;
执行该指令;
PC ++;
}

  • JVM是这样说的:
    1. Each Java Virtual Machine thread has its own pc (program counter) register.
    2. At any point, each Java Virtual Machine thread is executing the code of a single method, namely the current method for that thread.
    3. If that method is not native , the pc register contains the address of the Java Virtual Machine instruction currently being executed.

2、JVM stacks(重点)(线程私有)

  • JVM 是这样说的:

    1. Each Java Virtual Machine thread has a private Java Virtual
      Machine stack, created at the same time as the thread.
    2. A Java Virtual Machine stack stores frames
  • 每一个线程对应一个栈,每个方法对应一个栈针。JVM 虚拟机 所管理的

3、Native Method Stacks本地方法栈(线程私有)

  • JVM 是这样说的:

    1. An implementation of the Java Virtual Machine may use
      conventional stacks called native method stacks
  • c 和 c++。java 调用了 JNC ,调用了 c 和 c++时就会调用 ,没法调试和调优

4、Direct Memory

JDK 1.4 版本之后 ,增加了一个新的 Direct Memory 即直接内存,NIO的内容。 所有的内存都归java 虚拟机(JVM)直接管理,为了增加IO的效率,在JDK1.4之后增加了 DM(直接内存),从java虚拟机内部 可以访问操作系统管理的内存的。用户空间可以访问内核空间的内存

5、Method Area 方法区(重点)(线程公有)

a、MA

  • JVM 是这样说的:

    1. The Java Virtual Machine has a method area that is shared among all Java Virtual Machine threads.
    2. It stores per-class structures
  • 存储各种常量池,包含 :(JVM知识体系学习一中的常量池就是第一个 Class常量池)

    1. Class文件中的常量池
    2. 运行时常量池(run-time constant pool,运行之后Class文件中的常量池加载到内存即运行时常量池)
    3. 字符串常量池(1.7 和静态变量放到堆上)、
    4. 基本数据类型包装类常量池(Float 和Double 没有)、静态变量
  • JVM 版本的 方法区

    1. Perm Space 永久代 (<=JDK1.6版本)
      Class常量池、字符串常量池、运行时常量池、静态变量、基本数据类型包装类常量池 位于PermSpace
      不会触发FGC清理
      大小启动的时候指定,不能变
    2. Perm Space 永久代 (=JDK1.7版本,开始去永久代)
      字符串常量池、静态变量 转移到堆上,其他还在永久代
      不会触发FGC清理
    3. Meta Space 元空间 (>=JDK1.8版本)
      字符串常量池 位于堆
      会触发FGC清理
      不设定的话,最大就是物理内存

b、常量池

  • 常量池的资料
    • java中的常量池的分类:https://cloud.tencent.com/developer/article/1450501#

    • JAVA常量池,一篇文章就足够入门了。(含图解)https://blog.csdn.net/qq_41376740/article/details/80338158

    • JVM常量池主要分为 Class文件常量池运行时常量池全局字符串常量池,以及基本类型包装类对象常量池(Double和Folat这两种浮点数类型的包装类没有实现常量池技术)

    • 运行时常量池 中的常量是 运行之后 Class 文件中的常量池加载到MA中的。

c、JDK1.6、JDK1.7、JDK1.8 内存模型演变

  • JDK1.6、JDK1.7、JDK1.8 内存模型演变:https://www.cnblogs.com/xiaofuge/p/14244755.html
    JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第5张图片
  • JDK 1.6:有永久代,静态变量存放在永久代上。
  • JDK 1.7:有永久代,但已经把字符串常量池、静态变量,存放在堆上。开始去永久代。逐渐的减少永久代的使用。
  • JDK 1.8:无永久代,运行时常量池、类常量池,都保存在元数据区,也就是常说的元空间。但字符串常量池仍然存放在堆上。

6、Run-Time Constant Pool(属于MA)

  • JVM 是这样说的:
    1. A run-time constant pool is a per-class or per-interface run-time
      representation of the constant_pool table in a class file
  • 运行时常量池 位于方法区中

7、Heap 堆(线程共有)

  • JVM 是这样说的:
    1. The Java Virtual Machine has a heap that is shared among all Java Virtual Machine threads.
    2. The heap is the run-time data area from which memory for
      all class instances and arrays is allocated.

GC时好好聊:JVM知识体系学习六第三章: https://blog.csdn.net/qq_40036754/article/details/128651806

8、总体图

从下图看出:

  • PC、JVM stacks、native method stack 是线程独有的
  • heap、method area 是线程共享的
    JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第6张图片

二、java stack 中的 栈针Frame

  • A frame is used to store data and partial results, as well as to perform dynamic linking, return values for methods, and dispatch exceptions. (框架用于存储数据和部分结果,以及执行动态链接、方法的返回值和分派异常)
  • 每一个线程是一个栈针,每个方法对应一个栈帧,比如main()方法应该第一个进入栈中,调用的方法依次入栈(作为栈针)。
    JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第7张图片

1、栈针的四部分

  • 每一个栈针包括 以下四部分:
    JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第8张图片
    1. Local Variable Table:本地变量表
    2. Operand Stack:操作数栈
      • 对于long的处理(store and load),多数虚拟机的实现都是原子的
      • jls文档里 17.7,没必要加volatile
    3. Dynamic Linking:动态链接
      • 文档详解:https://blog.csdn.net/qq_41813060/article/details/88379473
      • jvms文档的 2.6.3
      • 就是class文件里的常量池 constant pool(常量池)里的符号链接,看有没有解析,如果没有解析就动态解析;如果解析了则直接使用,所以Dynamic Linking 就是这个东西。
      • 比如:有a()方法和b()方法,a()方法中调用了b()方法,那么执行a()方法中的b()方法时,则需要去常量池中去找b()方法,这个找的过程就是动态链接。 Dynamic Linking
    4. return address:返回地址。
      • a() 调用了 b(),方法a调用了方法b, b方法的返回值放在什么地方,这就是 return address。

2、Local Variable Table 局部变量表

a、问题引入的代码

package com.mashibing.jvm.c4_RuntimeDataAreaAndInstructionSet;

public class TestIPulsPlus {
    public static void main(String[] args) {
        int i = 8;
        i = i++;
//        i = ++i;
        System.out.println(i);
    }
}

b、查看字节码中的本地变量表

JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第9张图片
如上图所示:

  1. LineNumberTable:行号
  2. LocalVariableTable:本地变量表,包括两个,一个是main()方法的形参 args,一个是 变量 i
  3. 右边绿色的 cp info #15:cp,是 constant pool 常量池(在MA中);所以是常量池第15块地址存储的,可以点进去查看。
    JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第10张图片

3、Operand Stack(解释i++和++i的问题)

a、解释指令集:i++

先看下图的指令
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第11张图片
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第12张图片

  1. 指令一 bipush 8:(byte int push)就是 讲byte 转成 int 型 push 到栈中。即 将8 压入栈中。

    • 点击指令,可以直接进入到指令的解释网页
    • 下图
      JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第13张图片
  2. 指令二istore_1通过下面指令解释可以看出,将操作栈中的数出栈,赋值到局部变量表(二.2)中 下标为2的变量中。即将8出栈赋值到i上。

    • 指令解释如下
      JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第14张图片
      JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第15张图片
  3. 到了这儿,i=8 这条语句就执行完了,就是通过 1和 2这两条指令完成的。
    JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第16张图片

  4. 指令三 iload_1取出局部变量表下标为1的值,然后入操作栈;即 i=1取出,入操作栈。

    • 解释如下
      JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第17张图片
  5. 指令四 iinc 1 by 1局部变量表下标为1 的值 自加1。此时 局部变量表下标为1 的 i 值 变成了 9。

    • 解释
      JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第18张图片
  6. 指令五 istore_1同指令2,将操作栈中的值出栈,然后赋值到局部变量表下标为1的变量 i 上。所以将8赋值到局部变量表 i=9上,则为8。

  7. 此时,到这里,完美的解释了 i++ 的操作。i++ 的指令一共有三步,也就是第三、第四、第五个指令。

b、解释指令集:++i

执行的字节码如下图:唯一的不同,第三行和第四行交换了。 ++i 的指令也是第三、第四、第五个指令,共三个。

JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第19张图片
解释如下:

  1. bipush 8:将8压栈
  2. istore_1:8出栈,赋值到 局部变量表 下标为1 的 i 上,完成 i=8
  3. iinc 1 by 1:局部变量表下标为1 的i变量的值,自加1,完成 ++i,i = 9。
  4. iload_1:局部变量表下标为1 的i 变量 的值 9 取出,入操作栈。
  5. istore_1:操作栈 出栈,赋值 到 局部变量表 下标为1 的 i上,为9。

三、栈的执行流程

1、案例 1_sipush 指令

a、代码

在这里插入图片描述

b、字节码指令集

JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第20张图片

c、指令解说

和上面的案例相比,这里第一个指令是 sipush(原来是 bipush), 原因是: 200>127,所以不再是 byte 类型,而是 short 类型 转成 int 类型。

JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第21张图片

2、案例 2_局部变量表中的this

a、代码

在这里插入图片描述

b、字节码指令集

JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第22张图片

c、指令解说

  1. 第一个指令是 sipush 是正常的,因为300>127。
  2. 但是为什么第二个指令的下标变成2了呢,原因是: 只要是 非 static 方法都有一个 this 变量在局部变量表中,然后形参 k 是第二个,则 i 是第三个,所以这里的指令下标是 2
    JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第23张图片

前边的main 方法没有 this,是因为 main 方法有static。
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第24张图片

  • 要点:非static的局部变量表的第一个是this。

3、案例 3_加法指令_iadd

a、代码

JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第25张图片

b、字节码指令集

JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第26张图片

c、指令解说

  • 先说下局部变量表,有 this,a,b,c 共四个。
  • 指令描述如下:
    1. 指令 iload_1 iload_2 分别按顺序入操作栈 ;
    2. 指令iadd 则是将 int 类型的两个数出栈 相加 在入栈,此时栈中只有7;
    3. 指令 istore_3 则将操作栈 栈顶元素 7 出栈 赋值到局部变量表下标为 3c
      JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第27张图片

4、案例 4_创建对象指令

a、代码

JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第28张图片

b、字节码 指令集

m1()方法
在这里插入图片描述
main()方法
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第29张图片

c、指令解说

  • 从下图中也可以看出,线程栈中有两个栈针,一个 main() 方法,一个 m1() 方法。
  • 局部变量表:
    • main() 中:argsh
    • m1() 中:thisi
  • 执行顺序如下:
    1. new 指令先 创建一个对象(load、linking、initializing等初始化),
    2. dup 指令,复制操作数栈栈顶的值,再入操作数栈。此时操作数栈中有两个一样的 Hello_02 对象,都指向对象的地址。
    3. invokespecial 指令,是执行 默认的构造函数 init。到了这儿,对象构造才算完毕,然后弹出栈就没啦,此时操作数栈中只有一个对象了。(invoke 指令有五种,后面在讲)
    4. astore_1 指令(注意这里是 a 开头),是将操作数栈中的对象出栈 赋值h 上。
    5. aload_1 指令,从局部变量表中在取出 入操作数栈。
    6. invokevirtual 指令,执行 m1() 栈针,然后 出栈
      • 然后执行 sipush 200istore_1return 指令。然后返回地址
    7. 然后再执行,return 执行完即可。
  • 注意的点:
    • dup 指令:就是将操作栈中最上面的值复制一份,再压入操作栈中。
    • 半初始化状态,就是 newinvokevirtual 中间有个 dup 指令。

JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第30张图片
(上面main方法的栈针中的局部变量表中的this 错了,应该是args)

  • 可以想到 栈溢出(over stack)
  • 问题:DCL(双重检查,在JVM知识体系学习三 中有详细说明) 为什么要使用 volatile
    • 因为指令之间可能会指令重排

5、案例 5

a、案例5_1

i、代码

JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第31张图片

ii、字节码指令集

  1. m1方法:
    JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第32张图片
  2. main方法
    JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第33张图片

iii、指令解说

  • m1() 方法

    1. bipush:看文档;就是将 byte 转成 int 类型的值,压入操作数栈
    2. ireturn:返回int 值,并出栈
  • main() 方法

    1. 其余指令在上面案例中都讲过,我这里就稍微描述下
    2. new 需要仔细看文档 。开辟对象地址,并不是完整的创建对象,然后将对象引用入操作数栈。
    3. dup 复制对象引用入操作数栈。
    4. invokespecial:调用构造函数,完成对象初始化,并出栈,此时占中还有一个对象引用。
    5. astore_1:出栈,存储到局部变量表中下标为 1h 中。
    6. aload_1:取出下标为 1 的局部变量边的位置的值,入操作数栈。
    7. invokevirtual:调用 m1 方法
      • m1 的字节码指令集。
    8. pop函数,因为是返回,直接出栈即可。
  • 注意是main 方法 指令中倒数第二个指令,与下个案例做对比。

b、案例5_2

i、代码

JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第34张图片

ii、字节码指令集

m1方法(和上个案例一样)
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第35张图片
main方法
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第36张图片

iii、指令解说

  • 这里的指令与上一个案例只有一个地方不一样,就是main方法倒数第二个指令
  • 这里是将操作数栈中的值取出,然后赋值给局部变量表中下标为 2 的变量 i 中。

6、案例 6 (递归指令集解说)

a、代码

JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第37张图片

b、字节码指令集:

m方法:
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第38张图片
main方法
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第39张图片

c、指令解说

  • 有些难度,递归指令的描述。

四、常用指令

目前还没面试官问过,增长见识和知识点就OK。

1、常用命令

  1. store
  2. load
  3. pop
  4. mul
  5. sub
  6. invoke

2、invoke-共5个指令

  1. InvokeStatic:调用静态方法
    JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第40张图片

  2. InvokeVirtual:自带多态,执行类的成员方法。
    JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第41张图片

  3. InvokeInterface:调用接口方法。
    JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第42张图片

  4. InovkeSpecial

    • 可以直接定位,不需要多态的方法
    • private 方法 , 构造方法
      JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第43张图片
  5. InvokeDynamic

    • 1.7版本添加的指令,这时 java 开始支持动态语言。
    • JVM最难的指令
    • lambda表达式或者反射或者其他动态语言scala kotlin,或者CGLib ASM,动态产生的class,会用到的指令
    package com.mashibing.jvm.c4_RuntimeDataAreaAndInstructionSet;
    
    public class T05_InvokeDynamic {
        public static void main(String[] args) {
    
    
            I i = C::n;
            I i2 = C::n;
            I i3 = C::n;
            I i4 = () -> {
                C.n();
            };
            System.out.println(i.getClass());
            System.out.println(i2.getClass());
            System.out.println(i3.getClass());
    
            //for(;;) {I j = C::n;} //MethodArea <1.8 Perm Space (FGC不回收)
        }
    
        @FunctionalInterface
        public interface I {
            void m();
        }
    
        public static class C {
            static void n() {
                System.out.println("hello");
            }
        }
    }
    
    

    JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))_第44张图片

3、JDK1.8之前的一个BUG

  • for(;;) {I j = C::n;}
    • JDK 在小于1.8之前叫 Perm Space(永久代),这时上面的代码会产生大量的class类,会存放在 MethodArea(方法区),这时在1.8之前 MethodArea 会产生一个巨大的bugFGC(Full GC)不回收、不清理
    • 所以在JDK1.8之前,会产生OOM,内存溢出,但是在1.8之后,如果清除不掉,也会产生OOM。

你可能感兴趣的:(JVM,jvm,java,学习)