JVM是运行在操作系统之上的,它与硬件没有直接的交互

下图运行时数据区灰色代表线程私有,亮色(方法区和堆)代表所有线程共享。

1、类装载器ClassLoader

负责加载class文件,class文件在文件开头有特定的文件标示,将class文件字节码内容加载到内存中,并将这些内容转换成方法区中的运行时数据结构并且ClassLoader只负责class文件的加载,至于它是否可以运行,则由Execution Engine决定

虚拟机自带的加载器

启动类加载器(Bootstrap)C++

扩展类加载器(Extension)

Java 应用程序类加载器(AppClassLoader)Java也叫系统类加载器,加载当前应用的classpath的所有类

用户自定义加载器

Java.lang.ClassLoader的子类,用户可以定制类的加载方式

package com.yanshu;

/**
* @author :yangyuanyuan
* @description:TODO
* @date :2021/1/20 17:44
*/
class myObject{ public void test(){
System.out.println("Hello World!");
}
}
public class test {
public static void main(String[] args) {
Object o = new Object();
myObject myObject = new myObject();
//System.out.println(o.getClass().getClassLoader().getParent());//java.lang.NullPointerException
System.out.println(o.getClass().getClassLoader());//null 启动类加载器(Bootstrap) System.out.println(myObject.getClass().getClassLoader());//sun.misc.Launcher$AppClassLoader@18b4aac2
System.out.println(myObject.getClass().getClassLoader().getParent());//sun.misc.Launcher$ExtClassLoader@1540e19d
System.out.println(myObject.getClass().getClassLoader().getParent().getParent());//null 启动类加载器(Bootstrap)
}
}

双亲委派

当一个类收到了类加载请求,他首先不会尝试自己去加载这个类,而是把这个请求委派给父类去完成,每一个层次类加载器都是如此,因此所有的加载请求都应该传送到启动类加载器中,只有当父类加载器反馈自己无法完成这个请求的时候(在它的加载路径下没有找到所需加载的Class),子类加载器才会尝试自己去加载。 采用双亲委派的一个好处是比如加载位于 rt.jar 包中的类 java.lang.Object,不管是哪个加载器加载这个类,最终都是委托给顶层的启动类加载器进行加载,这样就保证了使用不同的类加载器最终得到的都是同样一个 Object对象。

2、执行引擎Execution Engine

执行引擎负责解释命令,提交操作系统执行。

3、Native Interface本地接口

native 求助外援,借助底层操作系统或第三方c语言函数库方法。

本地接口的作用是融合不同的编程语言为 Java 所用,它的初衷是融合 C/C++程序,Java 诞生的时候是 C/C++横行的时候,要想立足,必须有调用 C/C++程序,于是就在内存中专门开辟了一块区域处理标记为native的代码,它的具体做法是 Native Method Stack中登记 native方法,在Execution Engine 执行时加载native libraies。 目前该方法使用的越来越少了,除非是与硬件有关的应用,比如通过Java程序驱动打印机或者Java系统管理生产设备,在企业级应用中已经比较少见。因为现在的异构领域间的通信很发达,比如可以使用 Socket通信,也可以使用Web Service等等,不多做介绍。

4、Native Method Stack

它的具体做法是Native Method Stack中登记native方法,在Execution Engine 执行时加载本地方法库。

5、PC寄存器

每个线程都有一个程序计数器,是线程私有的,就是一个指针,指向方法区中的方法字节码(用来存储指向下一条指令的地址,也即将要执行的指令代码),由执行引擎读取下一条指令,是一个非常小的内存空间,几乎可以忽略不记。 这块内存区域很小,它是当前线程所执行的字节码的行号指示器,字节码解释器通过改变这个计数器的值来选取下一条需要执行的字节码指令。 如果执行的是一个Native方法,那这个计数器是空的。 用以完成分支、循环、跳转、异常处理、线程恢复等基础功能。不会发生内存溢出(OutOfMemory=OOM)错误

6、方法区

供各线程共享的运行时内存区域。它存储了每一个类的结构信息,例如运行时常量池(Runtime Constant Pool)、字段和方法数据、构造函数和普通方法的字节码内容。上面讲的是规范,在不同虚拟机里头实现是不一样的,最典型的就是永久代(PermGen space)和元空间(Metaspace)。 But 实例变量存在堆内存中,和方法区无关

7、栈

栈也叫栈内存,主管Java程序的运行,是在线程创建时创建,它的生命期是跟随线程的生命期,线程结束栈内存也就释放,对于栈来说不存在垃圾回收问题,只要线程一结束该栈就Over,生命周期和线程一致,是线程私有的。8种基本类型的变量+对象的引用变量+实例方法都是在函数的栈内存中分配。

栈帧中主要保存3 类数据:

本地变量(Local Variables):输入参数和输出参数以及方法内的变量;

栈操作(Operand Stack):记录出栈、入栈的操作;

栈帧数据(Frame Data):包括类文件、方法等等。

栈运行原理:

栈中的数据都是以栈帧(Stack Frame)的格式存在,栈帧是一个内存区块,是一个数据集,是一个有关方法(Method)和运行期数据的数据集,当一个方法A被调用时就产生了一个栈帧 F1,并被压入到栈中, A方法又调用了 B方法,于是产生栈帧 F2 也被压入栈, B方法又调用了 C方法,于是产生栈帧 F3 也被压入栈, …… 执行完毕后,先弹出F3栈帧,再弹出F2栈帧,再弹出F1栈帧…… 遵循“先进后出”/“后进先出”原则。

每个方法执行的同时都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息,每一个方法从调用直至执行完毕的过程,就对应着一个栈帧在虚拟机中入栈到出栈的过程。栈的大小和具体JVM的实现有关,通常在256K~756K之间,约等于1Mb左右。

图示在一个栈中有两个栈帧: 栈帧 2是最先被调用的方法,先入栈, 然后方法 2 又调用了方法1,栈帧 1处于栈顶的位置, 栈帧 2 处于栈底,执行完毕后,依次弹出栈帧 1和栈帧 2, 线程结束,栈释放。

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

package com.yanshu;

/**
* @author :yangyuanyuan
* @description:TODO
* @date :2021/1/22 10:16
*1 JVM系统架构图
*
* 2 类加载器
* System.out.println(myObject.getClass().getClassLoader());//sun.misc.Launcher$AppClassLoader@18b4aac2
* System.out.println(myObject.getClass().getClassLoader().getParent());//sun.misc.Launcher$ExtClassLoader@1540e19d
* System.out.println(myObject.getClass().getClassLoader().getParent().getParent());//null 启动类加载器(Bootstrap)
* 2.1 有哪几种类加载器
* 2.2 双亲委派
* 2.3 沙箱安全机制
*
* 3 Native
* 3.1 native是一个关键字
* 3.2 声明有,实现无 why
* private native void start0();
*
* 4 PC寄存器
* 4.1 记录了方法之间的调用和执行情况,类似排版值日表
* 用来存储指向下一条指令的地址,也即将要执行的指令代码
* 它是当前线程所执行的字节码的行号指示器
*
* 5 方法区
* 5.1 它存储了每一个类的结构信息(模板)
* 5.2 方法区是规范,在不同虚拟机里头实现是不一样的,最典型的就是永久代(PermGen space)和元空间(Metaspace)
*
* 空调 k1=new 格力()
* List list=new Arraylist()
*
* 方法区 f=new 永久代
* 方法区 f=new 元空间
*
* 6 stack
* 6.1 栈管运行,堆管存储
* 6.2 栈保存哪些东东
* 8种基本类型的变量+对象的引用变量+实例方法都是在函数的栈内存中分配。
*/
public class test3 {
public static void print(){
print(); } public static void main(String[] args) {
System.out.println("111");
print();
System.out.println("333");
new Thread().start(); }
}

java.lang.StackOverflowError 属于错误不是异常

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

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

Java堆中会存放访问类元数据的地址,

reference存储的就直接是对象的地址

JVM之JVM体系结构的更多相关文章

  1. jvm的内部体系结构浅析

    转自:http://www.cnblogs.com/evan2012/archive/2012/05/09/2489417.html 1.jvm的内部体系结构浅析 2.jvm的几个运行时数据区域 3. ...

  2. [转帖]JVM总结--JVM体系结构

    JVM总结--JVM体系结构 https://blog.csdn.net/samjustin1/article/details/52215274 需要不断的学习才可以. 2016年08月15日 22: ...

  3. 【JVM之内存与垃圾回收篇】JVM与Java体系结构

    JVM与Java体系结构 前言 作为Java工程师的你曾被伤害过吗?你是否也遇到过这些问题? 运行着的线上系统突然卡死,系统无法访问,甚至直接OOMM! 想解决线上JVM GC问题,但却无从下手. 新 ...

  4. JVM1 JVM与Java体系结构

    目录 JVM与Java体系结构 虚拟机与Java虚拟机 虚拟机 Java虚拟机 JVM的位置 JVM的整体结构 Java代码执行流程 JVM的架构模型 基于栈的指令级架构 基于寄存器的指令级架构 两种 ...

  5. JVM解毒——JVM与Java体系结构

    你是否也遇到过这些问题? 运行线上系统突然卡死,系统无法访问,甚至直接OOM 想解决线上JVM GC问题,但却无从下手 新项目上线,对各种JVM参数设置一脸懵逼,直接默认,然后就JJ了 每次面试都要重 ...

  6. JVM上篇:JVM与Java体系结构

    JVM笔记 JVM传言 Java不是最强大的语言,但是JVM是最强大的虚拟机 虚拟机分类 系统虚拟机 类似VMware,就属于系统虚拟机,它提供了一个可运行完整操作系统的平台 程序虚拟机 Java虚拟 ...

  7. Java -JVM:JVM百科

    ylbtech-Java -JVM:JVM百科 JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机 ...

  8. 【死磕JVM】JVM快速入门之前戏篇

    简介 Java是一门可以跨平台的语言,但是Java本身是不可以实现跨平台的,需要JVM实现跨平台.javac编译好后的class文件,在Windows.Linux.Mac等系统上,只要该系统安装对应的 ...

  9. JVM初探 -JVM内存模型

    JVM初探 -JVM内存模型 标签 : JVM JVM是每个Java开发每天都会接触到的东西, 其相关知识也应该是每个人都要深入了解的. 但接触了很多人发现: 或了解片面或知识体系陈旧. 因此最近抽时 ...

  10. 【JVM】JVM随笔索引

    JVM目录 [JVM]Java内存模型 [JVM]类加载机制 [JVM]深度分析Java的ClassLoader机制(源码级别) [JVM]关于类加载器准备阶段的一道面试题目 [JVM]JVM垃圾收集 ...

随机推荐

  1. i5 11300H和i5 10300H 的区别

    i5-11300H 为 4 核 8 线程,主频 3.1GHz,睿频 4.4GHz,三级缓存 8MB 选 i5-11300H还是i5 10300h 这些点很重要!看完你就知道了https://list. ...

  2. .Net微服务实战之负载均衡(下)

    系列文章 .Net微服务实战之技术选型篇 .Net微服务实战之技术架构分层篇 .Net微服务实战之DevOps篇 .Net微服务实战之负载均衡(上) .Net微服务实战之CI/CD .Net微服务实战 ...

  3. JVM 源码分析(二):搭建 JDK 8 源码调试环境(Windows 上使用 CLion)

    前言 一.准备源码 二.安装 "Bootstrap JDK" 三.配置编译环境 四.编译与测试 五.安装 CMake 和 GDB 五.准备远程调试 六.开始远程调试 前言 上一篇文 ...

  4. Databricks 第6篇:Spark SQL 维护数据库和表

    Spark SQL 表的命名方式是db_name.table_name,只有数据库名称和数据表名称.如果没有指定db_name而直接引用table_name,实际上是引用default 数据库下的表. ...

  5. selenium自动化 | 通过获取cookies登录

    >>>登录百度<<<#获取登录成功后的cookies def get_cookies(): driver.get(bd_url) driver.implicitly ...

  6. dmp文件导入抽取方法

    一.确认dmp文件.oracle客户端和服务端的字符集 (1)dmp文件字符集确认: 使用UE打开dmp文件查看文件第2个和第3个字节内容,这两个字节记录了dmp文件的字符集.如0354,然后用以下s ...

  7. centos7安装宝塔面板

    在终端下执行如下命令 yum install -y wget && wget -O install.sh http://download.bt.cn/install/install.s ...

  8. CyNix-lxd提权

    0x01 信息收集 nmap -p- -T5 192.168.43.155扫描开放端口 nmap -sV -p 80,6688 -A 192.168.43.155 -oA cynix扫描指定端口 go ...

  9. 02_Python基础

    2.1 第一条编程语句 print("Hello, Python!") print("To be, or not to be, it's a question." ...

  10. 十九、更改LCD显示屏

    一.裸机修改 之前测试用的屏幕是480*272的分辨率,现在要换成800*480的屏,因此要对软件代码进行修改. 对于裸机驱动而言,主要有两个点需要注意,一个是屏幕分辨率变了,因此初始化的时候与屏幕分 ...