JVM-内存与垃圾回收篇!女朋友看了都想当架构师的超详细保姆级笔记!呕心沥血之作!看完还不会你砍我!

1. JVM与Java体系结构

1.1 Java虚拟机

  1. Java虚拟机是一台执行Java字节码的虚拟计算机,它拥有独立的运行机制,其运行的Java字节码也未必由Java语言编译而成。
  2. JVM平台的各种语言可以共享Java虚拟机带来的跨平台性、优秀的垃圾回器,以及可靠的即时编译器。
  3. Java技术的核心就是Java虚拟机(JVM,Java Virtual Machine),因为所有的Java程序都运行在Java虚拟机内部。
  4. Java虚拟机就是二进制字节码的运行环境,负责装载字节码到其内部,解释/编译为对应平台上的机器指令执行。每一条Java指令,Java虚拟机规范中都有详细定义,如怎么取操作数,怎么处理操作数,处理结果放在哪里。
  5. 特点:一次编译、到处运行、自动垃圾回收功能

1.2 JVM

JVM位置

JVM-内存与垃圾回收篇!女朋友看了都想当架构师的超详细保姆级笔记!呕心沥血之作!看完还不会你砍我!

Java代码执行流程

JVM-内存与垃圾回收篇!女朋友看了都想当架构师的超详细保姆级笔记!呕心沥血之作!看完还不会你砍我!

JVM-内存与垃圾回收篇!女朋友看了都想当架构师的超详细保姆级笔记!呕心沥血之作!看完还不会你砍我!
  1. 类加载器子系统负责从文件系统或者网络中加载class文件,class文件在文件开头有特定的文件标识。

  2. classLoader只负责class文件的加载,至于它是否可以运行,则由ExecutionEngine(执行引擎)决定。

  3. 加载的类信息存放于一块称为方法区的内存空间。除了类的信息外,方法区中还会存放运行时常量池信息,可能还包括字符串字面量和数字常量(这部分常量信息是Class文件中常量池部分的内存映射)

    JVM-内存与垃圾回收篇!女朋友看了都想当架构师的超详细保姆级笔记!呕心沥血之作!看完还不会你砍我!

    2.3.1 过程1: Loading

    过程

    1. 通过一个类的全限定名获取定义此类的二进制字节流
    2. 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
    3. 在内存中生成一个代表这个类的java.lang.class对象,作为方法区这个类的各种数据的访问入口

    加载.class文件的方式

    1. 从本地系统中直接加载
    2. 通过网络获取,典型场景:web Applet
    3. 从zip压缩包中读取,成为日后jar、war格式的基础
    4. 运行时计算生成,使用最多的是:动态代理技术
    5. 由其他文件生成,典型场景:JSP应用
    6. 从专有数据库中提取.class文件,比较少见
    7. 从加密文件中获项,典型的防class文件被反编译的保护措施

    2.3.2 过程2: Linking

    JVM-内存与垃圾回收篇!女朋友看了都想当架构师的超详细保姆级笔记!呕心沥血之作!看完还不会你砍我!

    案例1

    JVM-内存与垃圾回收篇!女朋友看了都想当架构师的超详细保姆级笔记!呕心沥血之作!看完还不会你砍我!

    2.3 类加载器分类

    1. JVM支持两种类型的类加载器,分别为引导类加载器(Bootstrap ClassLoader)和自定义类加载器(User-Defined ClassLoader)。

    2. 从概念上来讲,自定义类加载器一般指的是程序中由开发人员自定义的一类类加载器,但是Java虚拟机规范却没有这么定义,而是将所有派生于抽象类ClassLoader的类加教器都划分为自定义类加载器。

      JVM-内存与垃圾回收篇!女朋友看了都想当架构师的超详细保姆级笔记!呕心沥血之作!看完还不会你砍我!

    2.3.1 三种类加载器

    JVM-内存与垃圾回收篇!女朋友看了都想当架构师的超详细保姆级笔记!呕心沥血之作!看完还不会你砍我!

    JVM-内存与垃圾回收篇!女朋友看了都想当架构师的超详细保姆级笔记!呕心沥血之作!看完还不会你砍我!

    2.4 双亲委派机制

    介绍

    ? Java虚拟机对class文件采用的是按需加载的方式,也就是说当需要使用该类时才会将它的class文件加载到内存生成class对象。而且加载某个类的class文件时,Java虚拟机采用的是双亲委派模式,即把请求交由父类处理,它是一种任务委派模式。

    工作原理

    1. 如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行;
    2. 如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器;
    3. 如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式。

    沙箱安全机制

    创建一个包java.lang,在里面自定义一个类String,那么这个类的全限定名就是java.lang.String,然后在测试类中new一个String,请问这个String,是自定义的还是java核心api中的/p>

    答案:核心api中的String

    原因:自定义类String,如果一运行,根据双亲委派机制,会首先由系统类加载器将其传递到扩展类加载器,然后再传递到引导类加载器,引导类加载器对java开头的都会进行加载,但是加载的还是api中的String,并不会加载自定义类的,这样可以保证对java核心源代码的保护,这就是沙箱保护机制

    例子

    JVM-内存与垃圾回收篇!女朋友看了都想当架构师的超详细保姆级笔记!呕心沥血之作!看完还不会你砍我!

    方法区和堆是有垃圾回收的

    JVM-内存与垃圾回收篇!女朋友看了都想当架构师的超详细保姆级笔记!呕心沥血之作!看完还不会你砍我!

    3.2 线程

    几个概念

    1. 线程是一个程序里的运行单元。JVM允许一个应用有多个线程并行的执行。
    2. 在Hotspot JVM里,每个线程都与操作系统的本地线程直接映射。当一个Java线程准备好执行以后,此时一个操作系统的本地线程也同时创建。Java线程执行终止后,本地线程也会回收。
    3. 操作系统负责所有线程的安排调度到任何一个可用的CPU上。一旦本地线程初始化成功,它就会调用Java线程中的run()方法。

    3.3 程序计数器(PC寄存器)

    概述

    1. PC寄存器用来存储指向下一条指令的地址,即将要执行的指令代码。由执行引擎读取下一条指令
    2. 它是一块很小的内存空间,几乎可以忽略不记。也是运行速度最快的存储区域。
    3. 在JVM规范中,每个线程都有它自己的程序计数器,是线程私有的,生命周期与线程的生命周期保持一致。
    4. 任何时间一个线程都只有一个方法在执行,也就是所谓的当前方法。程序计数器会存储当前线程正在执行的Java方法的JVM指令地址;或者,如果是在执行native方法,则是未指定值((undefned)。
    5. 它是程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。
    6. 字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令。
    7. 它是唯一一个在Java虚拟机规范中没有规定任何outOtMemoryError情况的区域。

    例子

    JVM-内存与垃圾回收篇!女朋友看了都想当架构师的超详细保姆级笔记!呕心沥血之作!看完还不会你砍我!

    3.4.2 常见异常及设置栈大小

    概念

    1. Java虚拟机规范允许Java栈的大小是动态的或者是固定不变的。

    2. 如果采用固定大小的Java虚拟机栈,那每一个线程的Java虚拟机栈容量可以在线程创建的时候独立选定。如果线程请求分配的栈容量超过Java虚拟机栈允许的最大容量,Java虚拟机将会抛出一个stackoverflowError异常。

    3. 如果Java虚拟机栈可以勤态扩展,并且在尝试扩展的时候无法中请到足够的内存,或者在创建新的线程时没有足够的内存去创建对应的虚拟机栈,那Java虚拟机将会抛出一个OutOfMemoryError异常。

    4. 我们可以使用参数**「-Xss+具体大小」**来设置线程的最大栈空间,栈的大小直接决定了函数调用的最大可达深度。

      JVM-内存与垃圾回收篇!女朋友看了都想当架构师的超详细保姆级笔记!呕心沥血之作!看完还不会你砍我!

    3.4.4 栈帧的内部结构

    1. 局部变量表(Local variables)
    2. 操作数栈(operand stack)(或表达式栈)
    3. 动态链接(Dynamic Linking)(或指向运行时常量池的方法引用)
    4. 方法返回地址(Return Address)(或方法正常退出或者异常退出的定义)
    5. 一些附加信息

    JVM-内存与垃圾回收篇!女朋友看了都想当架构师的超详细保姆级笔记!呕心沥血之作!看完还不会你砍我!

    JVM-内存与垃圾回收篇!女朋友看了都想当架构师的超详细保姆级笔记!呕心沥血之作!看完还不会你砍我!

    (下面LocalariableTable表详解)

    JVM-内存与垃圾回收篇!女朋友看了都想当架构师的超详细保姆级笔记!呕心沥血之作!看完还不会你砍我!
  4. 如果当前帧是由构造方法或者实例方法创建的,那么该对象引用this将套存放在index为0的slot处,其余的参数按照参数表顺序继续排列。(由于这一条的存在,因此在实际编码中,静态方法中是不可能用this的)

  5. 栈帧中的局部变量表中的槽位是可以重用的,如果一个局部变量过了其作用域,那么在其作用域之后申明的新的局部变量就很有可能会复用过期局部变量的槽位,从而达到节省资源的目的。

    来源:你的笑只是保护色

    声明:本站部分文章及图片转载于互联网,内容版权归原作者所有,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2021年7月21日
下一篇 2021年7月21日

相关推荐