qiyewuan

JVM体系结构概述

谈谈你对JVM的理解?java8的虚拟机有什么更新?

什么式OOM?什么式StackOverflowError?有那些方法分析?

JVM的常用参数调优你知道哪些?

内存快照抓取MAT分析DUMP文件知道吗?

谈谈JVM中,对类加载器你的认识?

JVM位置

image-20210813122230782

JVM体系结构图

image-20210813122655528

垃圾回收在橙色部分,生命周期比较长

类装载器就像是jvm的入口

类装载器 ClassLoader

image-20210813153812561

负责加载class文件,class文件在文件开头有特定的文件表示,并且ClassLoader只负责class文件的加载,至于它是否可以运行,则由Executin Engine决定

jvm的入口

类加载器的种类

image-20210813154416160

双亲委派机制

保证JVM不被加载的代码破坏,防止类的重复加载,保证Java核心包的类不被替换

启动类加载器是C++写的,java打印结果为null

public class Demo1 {
    public static void main(String[] args) {
        Object obj = new Object();
        Demo1 d01 = new Demo1();
     
        System.out.println(d01.getClass().getClassLoader().getParent().getParent());
        System.out.println(d01.getClass().getClassLoader().getParent());
        System.out.println(d01.getClass().getClassLoader());

        /**
         * null
         * sun.misc.Launcher$ExtClassLoader@1540e19d
         * sun.misc.Launcher$AppClassLoader@18b4aac2
         */
    }
}

沙箱安全机制

java中的安全模型-沙箱机制

执行引擎 Execution Engine

Execution Engine 执行引擎负责解释命令,提交给操作系统执行。jvm的出口

本地方法接口 Native Interface

image-20210813162626771

java里标native修饰的方法都没有方法体。比如Thread里的

private native void start0();交给操作系处理

new Thread().start(); //这行代码不能确定线程是否启动,因为是操作系统启动的

本地方法栈 Native Method Stack

本地方法栈是为虚拟机使用到的 Native 方法服务。虚拟机规范中对本地方法栈中的方法使用的语言、使用方式与数据结构并没有强制规定,因此具体的虚拟机可以自由实现它。

本地方法库

java调用Redis,MySQL等jar包统一需要本地方法库

windows系统玩单机游戏缺少dll,动态连接库

java执行不了的方法需要求助操作系统,把native标注的方法塞进本地方法栈,出栈时调用操作系统的本地方法接口,调接口时如果需要第三方的支持,使用本地方法库

image-20210813164047712

方法区 Method Area

方法区是所有线程共享所有字段和方法字节码,以及一些特殊方法和构造方法,接口代码也在此处定义。简单说,所有定义的方法都保存在此区域,此区域属于共享区间

class模版放在方法区中,Class类的东西都要放进去

静态变量 + 常量 + 类信息(构造方法/接口定义)+ 运行时常量池 存在方法区中

但是,实例变量存在堆内存中,和方法区无关

什么时候回收?jvm停下来的时候回收,生命周期很长。

java栈 java stack

与程序计数器是搭档

栈也叫栈内存,主管java程序的运行,是在线程创建的时候创建,它的生命周期是跟随线程的生命周期,线程结束的时候内存也就释放,对于栈来说不存在垃圾回收问题,只要线程一结束该栈就Over,生命周期和线程一致,是线程私有的

8种基本数据类型 + 对象的引用变量 +实例方法 都是在函数的栈内存中分配

栈存储什么?

栈帧主要保存三类数据:

本地变量 Local Variables 输入参数和输出参数以及方法內的变量

栈操作 Operand Stack 记录出栈,入栈的操作

栈帧数据 Frame Data 包括类文件,方法等

image-20210813171408385

每执行一个方法都会产生一个栈帧,保存到栈顶部,顶部栈就是当前的方法,该方法执行完毕后就会自动将此栈帧出栈main方法在栈底部

public class Demo1 {
    public static void main(String[] args) {
      test01();
        System.out.println("main end");
    }
    public static  void test01(){
        test02();
        System.out.println("test01 end");
    }

    public static void test02(){
        System.out.println("test02 end");
    }
}

/*
test02 end
test01 end
main end
*/
StackOverflowError

Exception in thread "main" java.lang.StackOverflowError

循环递归

栈 + 堆 + 方法区的交互关系

image-20210813172859010

HopSpot是使用指针的方式来访问对象:

Java堆中会存放访问类元数据的地址,reference存储的就是直接对象的地址

程序计数器 PC寄存器

每个线程都有一个程序计数器,是线程私有的(生命周期短,不需要垃圾回收),就是一个指针,指向方法区中的方法字节码(用来存储指向下一条指令的地址,也即将要执行的指令代码),由执行引擎读取下一条指令,是一个非常小的内存空间,几乎可以忽略不计

要注意,这个“堆”并不是数据结构意义上的堆(Heap (data structure),一种有序的树),而是动态内存分配意义上的堆——用于管理动态生命周期的内存区域。

JVM的堆被同一个JVM实例中的所有Java线程共享。它通常由某种自动内存管理机制所管理,这种机制通常叫做“垃圾回收”(garbage collection,GC)。JVM规范并不强制要求JVM实现采用哪种GC算法。

堆的数据结构更加复杂,jvm调优调的是堆

一个JVM实例只存在一个堆内存,堆内存的大小是可以调节的。类加载器读取了类文件后,需要把类,方法,常/变量放到堆内存中,保存所有引用类型的真实信息,以方便执行器执行,堆内存分为三部分:

  • Young Generation Space 新生区 Young/New

  • Tenure Generation Space 养老区 Old/Tenure

  • Permanent Space 永久区 Perm

Java 7之前

image-20210813192924579

新生区(幸存1区-> 养老区)经历GC(垃圾回收)之后,才能进入下面的区域

注意:养老区到永久存储区没有通路

image-20210813195459352

OutOfMemoryError

java.lang.OutOfMemoryError:java heap space异常

说明java虚拟机的堆内存不够

java.lang.OutOfMemoryError:PerGen space

程序启动大量需要加载的jar包。成为历史了

这两个异常也恰好说明新生区,养老区 和 元空间在内存不同的区域

image-20210813200803286

方法区是一个接口,永久区是方法区的一个实现

新生区:由Eden,两块大小相同的Survivor(又称为from/to,s0/s1)构成,to总为空

旧生代:存放新生代中经历多次GC仍然存活的对象
比如:连接池对象

image-20210813201627166

maven 配好就可以下载好相应的jar包

方法区接口有两个实现,1:永久区,2: 元空间
总结

在java7及之前,逻辑上分为三部分:新生区,养老区,永久区。新生区又可以分为伊甸区,幸存0区,幸存1区

在java8之后,逻辑上还是分为三部分:新生区,养老区,元空间

在物理上,分为两部分:新生区,养老区

image-20210813202826882

Java虚拟机的堆、栈、方法区如何去理解?

img

img

JAVA的JVM的内存可分为3个区:堆(heap)、栈(stack)和方法区(method)

  • 栈区:
  1. 每个线程包含一个栈区,栈中只保存方法中(不包括对象的成员变量)的基础数据类型和自定义对象的引用(不是对象),对象都存放在堆区中
  2. 每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问。
  3. 栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)。
  • 堆区:
  1. 存储的全部是对象实例,每个对象都包含一个与之对应的class的信息(class信息存放在方法区)。
  2. jvm只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身,几乎所有的对象实例和数组都在堆中分配。
  • 方法区:
  1. 又叫静态区,跟堆一样,被所有的线程共享。它用于存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

作者:EnjoyMoving
链接:https://www.zhihu.com/question/29833675/answer/207261960
来源:知乎

堆参数调优

jvm运行起来占用内存多少?

image-20210813205440209

image-20210813205512762

-Xms 本机内存的64分之一

-Xmx 本机内存的4分之一

分类:

技术点:

相关文章:

  • 2020-06-30
  • 2021-09-23
  • 2021-04-15
  • 2021-10-16
  • 2021-10-12
  • 2022-01-21
  • 2021-08-07
  • 2018-09-02
猜你喜欢
  • 2021-10-03
  • 2019-12-31
  • 2021-05-15
  • 2021-09-29
  • 2021-04-26
相关资源
相似解决方案