JVM学习笔记1:JVM架构及其原理

一、什么是JVM?

JVM(Java Virtual Machine,Java虚拟机)

       虚拟机是一种抽象化的计算机,通过在实际的计算机上仿真模拟各种计算机功能来实现的。Java虚拟机有自己完善的硬体架构,如处理器、堆栈、寄存器等,还具有相应的指令系统。Java虚拟机屏蔽了与具体操作系统平台相关的信息,使得Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。

  • 简单来说JVM是用来解析和运行Java程序的。

       Java语言的一个非常重要的特点就是与平台的无关性。而使用Java虚拟机是实现这一特点的关键。一般的高级语言如果要在不同的平台上运行,至少需要编译成不同的目标代码。而引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。这就是Java的能够“一次编译,到处运行”的原因。

二、JVM的体系结构

1.JVM的位置

2.JVM简单体系结构图:

JVM详细体系结构图:

三、类装载器(Class Loader)

1.类装载器是什么?

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

2.用来干嘛?

用上面的Car实例来解释:

  • Car.class 是由 .java 文件 经过编译而得来的 .class文件,存在本地磁盘;
  • ClassLoader: 类装载器,作用就是加载并初始化 .class文件 ,得到真正的 Class 类,即模板;
  • Car Class : 由 Car.class 字节码文件,通过ClassLoader 加载并初始化而得,那么此时 这个 Car 就是当前类的模板,这个Car Class 模板就存在 【方法区】;
  • car1,car2,car3 : 是由Car模板经过实例化而得,即 new出来的 --> Car car1 = new Car();
  • car1.getClass 可以得到其模板Car 类,Car.getClassLoader() 可得到其装载器。

3.类装载器的种类

  1. 启动类加载器 也叫根加载器 (Bootstrap),由C++编写 ,程序中自带的类, 存储在$JAVAHOME/jre/lib/rt.jar中,如object类等;
  2. 扩展类加载器Extension),Java 编写 ,在我们平时看到的类路径中,凡是以javax 开头的,都是拓展包,存储在$JAVAHOME/jre/lib/ext/*.jar 中;
  3. 应用程序类加载器AppClassLoader),即平时程序中自定义的类 new出来的。

4.java类的加载机制

启动类加载器 --> 拓展类加载器 --> 应用程序类加载器

四、双亲委派机制

1.概念:

  1. 类加载器收到类加载请求;
  2. 将这个请求向上委托给父类加载器去完成,一直向上委托,直到启动类加载器;
  3. 启动类加载器检查是否能够加载当前这个类,能加载就结束,使用当前加载器;否则,抛出异常,通知子加载器进行加载;
  4. 重复步骤3.
  • 采用双亲委派的一个好处就是比如加载位于rt.jar包中的类java.lang.Object,不管是哪个加载器加载这个类,最终都是会委托给顶层的启动类加载器进行加载,这样就保证了使用不同的类加载器最终得到的都是同一个Object对象。

五、沙箱安全机制

1.是什么?

限制程序运行的一些环境。

       当前最新的安全机制实现,则引入了域 (Domain) 的概念。虚拟机会把所有代码加载到不同的系统域和应用域,系统域部分专门负责与关键资源进行交互,而各个应用域部分则通过系统域的部分代理来对各种需要的资源进行访问。虚拟机中不同的受保护域 (Protected Domain),对应不一样的权限 (Permission)。

六、本地方法接口 (JNI :Native Interface)

1.native是什么?

native:在Java中是一个关键字,有声明,无实现。

凡是带了native关键字的,说明Java的作用达不到了,会去调用底层C语言的库(native libraies)。

  1. 先进入本地方法栈;
  2. 再调用本地方法本地接口JNI;

2.JNI作用

 

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

七、PC寄存器(程序计数器)(PC Registers)

1.是什么?

 

记录了方法之间的调用和执行情况,类似班级的值日表,用来存储指向下一条指令的地址,也即将要执行的指令代码。(每一个线程都有一个私有的程序计数器)

八、方法区(Method Area)

1.是什么?

供各线程共享的运行时内存区域。存储了每一个类的结构信息(模板)。

什么数据会存在方法区: 静态变量static、常量final、类信息class(构造方法、接口定义),运行时的常量池都存在方法区中,但实例变量存储在堆内存中,和方法区无关。

九、栈(Stack)

1.是什么?

       栈也叫栈内存,主管Java程序的运行,是在线程创建时创建,他的生命周期是跟随线程的生命周期,线程结束那么栈内存也就随之释放, 对于栈来说不存在垃圾回收问题 ,只要线程已结束该栈就over了, 是线程私有的。

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

2.栈存储什么?

       栈帧(Stack Frame)中主要保存 3 类数据 : (何为栈帧:即Java中的方法,只是在jvm中叫做栈帧)

  • 本地变量 (Local Variables) : 入参和出参 以及方法内的变量;
  • 栈操作 (Operand Stack) : 记录出栈 和 入栈的操作;(可理解为pc寄存器的指针);
  • 栈帧数据 (Frame Data) : 包括类文件、方法等。

3.栈的运行原理——“先进后出,后进先出”

  • 栈中的数据都是以栈帧 (Stack Frame) 的格式存在,栈帧是一个内存区块,是一个有关方法和运行期数据的数据集;
  • 每个方法执行的同时都会创建一个栈帧,用于存储局部变量表,操作数据栈,动态连接、方法出口等信息,每一个方法从调用直至执行完毕的过程,就对应着一个栈帧在虚拟机中入栈到出栈的操作过程。

十、堆(Heap)

1.是什么?

       堆(Heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵完全二叉树的数组对象。

2.堆区

  • 存储的全部都是对象,每个对象包含了一个与之对应的 class 类的信息。
  • jvm 只有一个堆区(steap),它会被所有线程共享,堆中不存放基本数据类型和对象引用,它只存放对象本身。

3.堆的划分

        Java虚拟机根据对象存活的周期不同,把堆内存划分为几块,一般分为新生代Young老年代Old永久代Permanent(对HotSpot虚拟机而言,JDK1.8之后为元空间metaspace替代永久代),这就是JVM的内存分代策略。

  • 新生代(Young Generation)
        新生代含有3个区域,1个Eden区,2个Survivor区,可以分别称为from以及to区,from与to的大小相同。它
    们占用的大小比例默认为Eden:from:to=8:1:1,当然也可以通过参数-XX:SurvivorRatio来自定义比例。
    
        新创建的对象都会处在Eden区,大对象会直接进入老年代,可以使用参数-XX:+PretenuerSizeThreshold来
    指定多大的对象。
    
        新创建的对象优先在Eden区上分配,Eden区满了之后,会触发一次Minor GC,虚拟机会采用复制算法(不会
    产生内存碎片)先进行释放内存,回收死亡对象,然后将存活的对象一次性复制进from区域中。若from区域不
    够,则使用分派担保机制将部分对象直接推入老年代。老年代空间不够,将触发一次Full GC。
    
        发生过一次Minor GC之后,Eden区域基本空闲,新创建的对象依然在这块区域上分配,当Eden区域又满了之
    后,同样还是出发第二次Minor GC,这次GC将会回收Eden与from区域,将存活的对象一次性地复制进to区域中。
    
        这些对象在新生代中每熬过一次Minor GC,对象的年龄就会加1,当年龄达到某一个阈值时(默认为15),将
    会被直接移到老年代中,可以使用参数-XX:MaxTenuringThreshold来指定这个阈值。
    
        因为新生代区域上对象,创建频繁,死亡也频繁,因此Minor GC也会变得十分频繁,但是这种GC方式效率
    高,持续时间短。
    

     

  • 老年代(Old Generationn)
  •     老年代中主要有老年对象(超过年龄阈值的对象)以及大对象。当老年代空间不足时,会触发一次Full GC,
    由于各个垃圾收集器的实现不同或处于效率考虑,可能会采用标记清除算法,也可能采用标记整理的算法回收死亡
    对象。
    
        当然,也不是对象必须达到年龄阈值才会进入老年代中,如果Survivor内某个相同年龄下(比如10岁)的所
    有对象的大小总和超过Survivor区的一半,那么年龄≥10岁的对象将直接进入老年代中。
    
        Full GC不像Minor GC那么频繁,但持续时间长。倘若频繁发生Full GC,会严重阻碍应用程序的执行。

     

  • 永久代(Permanent Generationn):永久代存储类信息、常量、静态变量、即时编译器编译后的代码等数据,对这一区域而言,Java虚拟机规范指出可以不进行垃圾收集,一般而言不会进行垃圾回收。关闭VM就会释放这个区域内存。

4.堆区的作用

       堆内存是虚拟机管理的内存中最大的一块,也是垃圾回收最频繁的一块区域,我们程序所有的对象实例都存放在堆内存中。给堆内存分代是为了提高对象内存分配和垃圾回收的效率。试想一下,如果堆内存没有区域划分,所有的新创建的对象和生命周期很长的对象放在一起,随着程序的执行,堆内存需要频繁进行垃圾收集,而每次回收都要遍历所有的对象,遍历这些对象所花费的时间代价是巨大的,会严重影响我们的GC效率。
  有了内存分代,情况就不同了,新创建的对象会在新生代中分配内存,经过多次回收仍然存活下来的对象存放在老年代中,静态属性、类信息等存放在永久代中,新生代中的对象存活时间短,只需要在新生代区域中频繁进行GC,老年代中对象生命周期长,内存回收的频率相对较低,不需要频繁进行回收,永久代中回收效果太差,一般不进行垃圾回收,还可以根据不同年代的特点采用合适的垃圾收集算法。分代收集大大提升了收集效率,这些都是内存分代带来的好处。

十一、垃圾回收(GC)(只在堆和方法区中有)

1.GC-引用计数法

:利用计数器对每个对象的使用次数进行记录,对象的次数为0则被垃圾回收。但这种算法不好,有消耗,很少使用。

2.GC- 复制算法

       将活着的内存空间分为两块,每次只使用其中一块,在垃圾回收时将正在使用的内存中的存活对象复制到未被使用的内存块中,之后清除正在使用的内存块中的所有对象,交换两个内存的角色,最后完成垃圾回收。

优点:没有内存碎片;

缺点:浪费了内存空间;

3.GC- 标记清除算法

       清除算法由标记阶段和清楚阶段构成,在标记阶段会把所有的活动对象都做上标记,然后在清除阶段会把没有标记的对象,也就是非活动对象回收。

优点:不需要额外空间;

缺点:两次扫描严重浪费时间,会产生内存碎片;

标记压缩(防止内存碎片产生)

缺点:多了一个移动成本;

4.GC算法总结

内存效率:复制算法 > 标记清除算法 > 标记压缩算法(时间复杂度);

内存整齐度:复制算法 = 标记压缩算法 >标记清除算法;

内存利用率:标记压缩算法 = 标记清除算法 > 复制算法;

年轻代:存活率低 --> 复制算法;

老年代:区域大 --> 标记清除算法(内存碎片不是太多的时候用)+标记压缩算法 混合实现;

 

2019最新深入理解JVM内存结构及运行原理JVM调优)高级核心课程视频教程下载。JVMJava知识体系中的重要部分,对JVM底层的了解是每一位Java程序员深入Java技术领域的重要因素。本课程试图通过简单易懂的方式,系统的深入讲解JVM相关知识。包括JVM执行过程、虚拟机类加载机制、运行时数据区、GC、类加载器、内存分配与回收策略等,全套视频加资料高清无密码  第1讲 说在前面的话 免费 00:05:07  第2讲 整个部分要讲的内容说明 免费 00:06:58  第3讲 环境搭建以及jdk,jre,jvm的关系 免费 00:20:48  第4讲 jvm初体验-内存溢出问题的分析与解决 免费 00:17:59  第5讲 jvm再体验-jvm可视化监控工具 免费 00:21:17  第6讲 杂谈 免费 00:12:37  第7讲 Java的发展历史 00:27:24  第8讲 Java的发展历史续 00:02:27  第9讲 Java技术体系 00:08:46  第10讲 jdk8的新特性 00:07:31  第11讲 lanmbda表达式简介 00:07:02  第12讲 Java虚拟机-classic vm 00:06:06  第13讲 Java虚拟机-ExactVM 00:03:35  第14讲 Java虚拟机-HotSpotVM 00:04:23  第15讲 Java虚拟机-kvm 00:03:04  第16讲 Java虚拟机-JRockit 00:04:12  第17讲 Java虚拟机-j9 00:04:23  第18讲 Java虚拟机-dalvik 00:02:20  第19讲 Java虚拟机-MicrosoftJVM 00:03:57  第20讲 Java虚拟机-高性能Java虚拟机 00:02:58  第21讲 Java虚拟机-TaobaoVM 00:03:06  第22讲 Java内存区域-简介 00:07:56  第23讲 Java内存区域-Java虚拟机栈 00:12:04  第24讲 Java内存区域-程序计数器 00:12:54  第25讲 Java内存区域-本地方法栈 00:02:39  第26讲 Java内存区域-堆内存 00:05:08  第27讲 Java内存区域-方法区 00:06:32  第28讲 Java内存区域-直接内存和运行时常量池 00:15:53  第29讲 对象在内存中的布局-对象的创建 00:21:19  第30讲 探究对象的结构 00:13:47  第31讲 深入理解对象的访问定位 00:08:01  第32讲 垃圾回收-概述 00:06:20  第33讲 垃圾回收-判断对象是否存活算法-引用计数法详解 00:14:08  第34讲 垃圾回收-判断对象是否存活算法-可达性分析法详解 00:07:09  第35讲 垃圾回收算法-标记清除算法 00:04:36  第36讲 垃圾回收算法-复制算法 00:14:35  第37讲 垃圾回收算法-标记整理算法和分代收集算法 00:05:24  第38讲 垃圾收集器-serial收集器详解 00:09:45  第39讲 垃圾收集器-parnew收集器详解 00:04:53  第40讲 垃圾收集器-parallel收集器详解 00:11:02  第41讲 垃圾收集器-cms收集器详解 00:14:58  第42讲 最牛的垃圾收集器-g1收集器详解 00:18:04  第43讲 内存分配-概述 00:04:23  第44讲 内存分配-Eden区域 00:22:51  第45讲 内存分配-大对象直接进老年代 00:06:42  第46讲 内存分配-长期存活的对象进入老年代 00:03:40  第47讲 内存分配-空间分配担保 00:04:54  第48讲 内存分配-逃逸分析与栈上分配 00:10:32  第49讲 虚拟机工具介绍 00:10:27  第50讲 虚拟机工具-jps详解 00:11:20  第51讲 虚拟机工具-jstat详解 00:09:20  第52讲 虚拟机工具-jinfo详解 00:05:03  第53讲 虚拟机工具-jmap详解 00:08:48  第54讲 虚拟机工具-jhat详解 00:08:10  第55讲 虚拟机工具-jstack详解 00:10:19  第56讲 可视化虚拟机工具-Jconsole内存监控 00:07:09  第57讲 可视化虚拟机工具-Jconsole线程监控 00:12:18  第58讲 死锁原理以及可视化虚拟机工具-Jconsole线程死锁监控 00:10:38  第59讲 VisualVM使用详解 00:08:03  第60讲 性能调优概述 00:11:22  第61讲 性能调优-案例1 00:23:28  第62讲 性能调优-案例2 00:10:05  第63讲 性能调优-案例3 00:12:41  第64讲 前半部分内容整体回顾 00:15:41  第65讲 Class文件简介和发展历史 免费 00:11:26  第66讲 Class文件结构概述 免费 00:16:50  第67讲 Class文件设计理念以及意义 免费 00:13:41  第68讲 文件结构-魔数 免费 00:09:49  第69讲 文件结构-常量池 免费 00:23:44  第70讲 文件结构-访问标志 免费 00:11:36  第71讲 文件结构-类索引 00:11:26  第72讲 文件结构-字段表集合 00:13:21  第73讲 文件结构-方法表集合 00:10:06  第74讲 文件结构-属性表集合 00:18:23  第75讲 字节码指令简介 00:09:18  第76讲 字节码与数据类型 00:09:34  第77讲 加载指令 00:09:33  第78讲 运算指令 00:10:24  第79讲 类型转换指令 00:13:42  第80讲 对象创建与访问指令 00:09:38  第81讲 操作树栈指令 00:03:27  第82讲 控制转移指令 00:11:58  第83讲 方法调用和返回指令 00:06:37  第84讲 异常处理指令 00:09:44  第85讲 同步指令 00:07:34  第86讲 类加载机制概述 00:07:26  第87讲 类加载时机 00:13:15  第88讲 类加载的过程-加载 00:15:15  第89讲 类加载的过程-验证 00:10:24  第90讲 类加载的过程-准备 00:05:40  第91讲 类加载的过程-解析 00:14:04  第92讲 类加载的过程-初始化 00:19:41  第93讲 类加载器 00:22:41  第94讲 双亲委派模型 00:17:03  第95讲 运行时栈帧结构 00:08:46  第96讲 局部变量表 00:20:48  第97讲 操作数栈 00:08:36  第98讲 动态连接 00:02:56  第99讲 方法返回地址和附加信息 00:03:24  第100讲 方法调用-解析调用 00:09:49  第101讲 方法调用-静态分派调用 00:16:21  第102讲 方法调用-动态分派调用 00:09:02  第103讲 动态类型语言支持 00:09:27  第104讲 字节码执行引擎小结 00:03:38  第105讲 总结与回顾 00:10:55  第106讲 happens-before简单概述 00:15:17  第107讲 重排序问题 00:23:19  第108讲 锁的内存语义 00:13:54  第109讲 volatile的内存语义 00:12:04  第110讲 final域内存语义
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值