JVM总览- JVM架构

JVM基础篇1 - Class的加载
JVM基础篇2 - 指令集
JVM进阶篇1 - 内存模型
JVM进阶篇2 - GC垃圾回收
JVM总览- JVM架构

1.JVM架构图

第三方插件基本都是在 类加载器或执行引擎上动手

在这里插入图片描述

2. jvm的位置:

在这里插入图片描述

3. jvm结构体系

在这里插入图片描述

在这里插入图片描述

4. 类加载器: 加载Class文件

在这里插入图片描述

  1. 虚拟机自带的加载器
  2. 启动类 (根) 加载器
  3. 扩展类加载器
  4. 应用程序加载器

app—>扩展类(ext) ----> (启动类)根加载器(rt) —>

  1. 类加载器收到类加载的请求
  2. 将这个请求向上委托给父类加载器去完成, 一直向上委托, 直到启动类加载器(根加载器rt)
  3. 启动类加载器检查是否能够加载当前这个类, 能够加载就结束了, 使用当前加载器,否则抛出异常,通知子类加载器进行加载.
  4. 重复步骤3

双亲委派机制:

在这里插入图片描述

从上图中我们就更容易理解了,当一个Hello.class这样的文件要被加载时。不考虑我们自定义类加载器,首先会在AppClassLoader中检查是否加载过,如果有那就无需再加载了。如果没有,那么会拿到父加载器,然后调用父加载器的loadClass方法。父类中同理也会先检查自己是否已经加载过,如果没有再往上。注意这个类似递归的过程,直到到达Bootstrap classLoader之前,都是在检查是否加载过,并不会选择自己去加载。直到BootstrapClassLoader,已经没有父加载器了,这时候开始考虑自己是否能加载了,如果自己无法加载,会下沉到子加载器去加载,一直到最底层,如果没有任何加载器能加载,就会抛出ClassNotFoundException。那么有人就有下面这种疑问了?

为什么要设计这种机制?

这种设计有个好处是,如果有人想替换系统级别的类:String.java。篡改它的实现,在这种机制下这些系统的类已经被Bootstrap classLoader加载过了(为什么?因为当一个类需要加载的时候,最先去尝试加载的就是BootstrapClassLoader),所以其他类加载器并没有机会再去加载,从一定程度上防止了危险代码的植入

5. 沙箱安全机制

Java安全模型的核心就是Java沙箱(sandbox),什么是沙箱?沙箱是一个限制程序运行的环境。沙箱机制就是将 Java 代码限定在虚拟机(JVM)特定的运行范围中,并且严格限制代码对本地系统资源访问,通过这样的措施来保证对代码的有效隔离,防止对本地系统造成破坏。沙箱主要限制系统资源访问,那系统资源包括什么?——CPU、内存、文件系统、网络。不同级别的沙箱对这些资源访问的限制也可以不一样。

组成沙箱的基本组件:
  • 字节码校验器(bytecode verifier):确保Java类文件遵循Java语言规范。这样可以帮助Java程序实现内存保护。但并不是所有的类文件都会经过字节码校验,比如核心类。

  • 类装载器

    (class loader):其中类装载器在3个方面对Java沙箱起作用

    • 它防止恶意代码去干涉善意的代码;
    • 它守护了被信任的类库边界;
    • 它将代码归入保护域,确定了代码可以进行哪些操作。

虚拟机为不同的类加载器载入的类提供不同的命名空间,命名空间由一系列唯一的名称组成,每一个被装载的类将有一个名字,这个命名空间是由Java虚拟机为每一个类装载器维护的,它们互相之间甚至不可见。

类装载器采用的机制是双亲委派模式

  1. 从最内层JVM自带类加载器开始加载,外层恶意同名类得不到加载从而无法使用;
  2. 由于严格通过包来区分了访问域,外层恶意的类通过内置代码也无法获得权限访问到内层类,破坏代码就自然无法生效。
  • 存取控制器(access controller):存取控制器可以控制核心API对操作系统的存取权限,而这个控制的策略设定,可以由用户指定。

  • 安全管理器(security manager):是核心API和操作系统之间的主要接口。实现权限控制,比存取控制器优先级高。

  • 安全软件包'(security package):java.security下的类和扩展包下的类,允许用户为自己的应用增加新的安全特性,包括:

  • 安全提供者

  • 消息摘要

  • 数字签名

  • 加密

  • 鉴别

6.native :凡是带了native关键字,说明java的作用范围达不到了,回去调用底层C语言的库

private native void start0();

  • 会进入本地方法栈,调用本地方法,本地接口 JNI(java native interface)
  • JNI的作用:扩展java的使用,融合不同的编程语言为java所用
  • 他在内存区域中专门开辟了一块标记区域 :Native Method Stack 登记native方法,在最终执行的时候,加载本地方法库中的方法通过JNI
pc寄存器

在这里插入图片描述

Method Area 方法区

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

静态变量(static),常量(final),类信息(Class构造方法,接口定义),运行时的常量池存在方法区中, 但是实例变量存在堆内存中,和方法区无关.

对象实例化过程:

JDK8 HotSpot JVM 使用本地内存来存储类元数据信息并称之为:元空间(Metaspace)

在这里插入图片描述

7. 堆:Heap, 一个JVM只有一个堆内存,堆内存的大小是可以调节的。

类加载器读取了类文件后,一般会把什么东西放到堆中?
类, 方法,常量,变量~,保存我们所有引用类型的真实对象;
堆内存中还要细分为三个区域:
●新生区(伊甸园区) Young/New
●养老区old
●永久区Perm(JDK1.8中已经被移除,被方法区的元空间取代)

在这里插入图片描述

GC垃圾回收,主要是在伊甸园区和养老区~
假设内存满了,OOM,堆内存不够! java.lang.OutOfMemoryError:Java heap space
永久存储区里存放的都是Java自带的 例如lang包中的类 如果不存在这些,Java就跑不起来了
在JDK8以后,永久存储区改了个名字(元空间)

新生区

●类诞生和成长的地方,甚至死亡;
●伊甸园,所有的对象都是在伊甸园区new出来的!
●幸存者区(0,1)(from区 to区)

在这里插入图片描述

伊甸园满了就触发轻GC,经过轻GC存活下来的就到了幸存者区,幸存者区满之后意味着新生区也满了,则触发重GC,经过重GC之后存活下来的就到了养老区。

真理:经过研究,99%的对象都是临时对象!|

永久区

这个区域常驻内存的。用来存放JDK自身携带的Class对象。Interface元数据,存储的是Java运行时的一些环境~ 这个区域不存在垃圾回收,关闭虚拟机就会释放内存
●jdk1.6之前:永久代,常量池是在方法区;
●jdk1.7:永久代,但是慢慢的退化了,去永久代,常量池在堆中
●jdk1.8之后:无永久代,常量池在元空间

在这里插入图片描述

元空间:逻辑上存在,物理上不存在 (因为存储在本地磁盘内) 所以最后并不算在JVM虚拟机内存中

猜你喜欢

转载自blog.csdn.net/The_xiaoke/article/details/124317798
JVM