JVM介绍

JVM基础知识

1.Java的跨平台特性

在这里插入图片描述

  • JVM是用C/C++开发,编译生成机器码,不能跨平台,不同的平台需要安装不同的JVM。
  • Java源码编译会生成字节码.class文件,JVM负责将字节码文件翻译成特定平台下的机器码进行执行,实现了“一次编译、到处运行”的目的
    实现跨平台特性是Java程序,不是JVM

2.JVM概念

  • JVM(Java Virtual Machine)即Java虚拟机
  • JVM是Java的核心和基础,在Java编译器和系统之间虚拟出来的机器,是利用了软件方法实现了计算机下层的操作系统和硬件平台,可以在上面执行的java的字节码程序
  • 具有自己的硬件架构,比如处理器、堆栈以及指定系统,使用JVM的目的是让java能支持与操作系统无关可以跨平台的特征

3.JRE/JDK/JVM介绍

  • JVM:是一个虚拟出来的计算机,通过软件实现在一个实际的计算机上模拟各种计算机的功能,它是属于JRE的一部分
  • JRE(Java Runtime Environment,java运行环境):也成为了Java平台,所有的Java程序都在JRE下才能运行
  • JDK(Java Development Kit,Java开发工具包):程序开发过程中需要编译,调试java程序用到的工具包,JDK的工具包也是Java程序,也需要在JRE上运行,为了保证JDK的独立性和完整性,在JDK的安装过程中,JRE也是安装的一部分,所以,在JDK的安装目录下有一个jre目录,存放JRE文件。
    在这里插入图片描述
    在这里插入图片描述

4.JVM生命周期

  • java虚拟机实例通过调用某个初始类来main方法来运行Java程序,main()必须是共有的(public)、静态的(static)、返回值为void,并且接收一个字符串数组作为参数,任何拥有main方法的类都可以作为Java程序的运行起点。
  • 当前mian方法程序执行结束,JVM实例也随之消亡

JVM工作过程

Java代码执行过程:
在这里插入图片描述

JVM工作过程

在这里插入图片描述
加载类的整个过程分为3个子系统:

  • 类加载系统(ClassLoader SubSystem)
  • 运行时数据区(Runtime Data Areas)
  • 执行引擎(Execution Engine)
(1)类加载子系统

Java类状态过程包含三部分,装载、链接、初始化
装载: 主要功能是完成类加载,通过BootStrap ClassLoader、Extension ClassLoader、Application ClassLoader加载器和双亲委派模型完成特定类加载
链接: a)验证:字节码验证器将验证生成的字节码是否正确,如果验证失败,将得到验证失败提示
b)准备:对于所有静态变量,内存将分配内存空间并给定初始值
c)解析:所有的符号引用转化为方法区内的原始引用
初始化: 将静态变量赋予原始值

(2)运行时数据区域

方法区: 类别级数据、静态编码,线程共享区域
堆区: 创建对象及数组存储位置,线程共享区域
虚拟机栈: 线程私有区域
本地方法栈: 存储调用native的方法,线程私有区域
程序计数器: 指示代码执行的位置,线程私有区域

(3)执行引擎

执行引擎将运行时数据区域存储的字节码交由执行引擎执行,执行引擎读取字节码并逐个执行

类加载机制

Java中类加载是需要加载编译之后的.class的字节码文件,JVM虚拟机通过解释器能够将字节码解释为特定机器上的机器码
Java源代码–>编译器–>字节码–>JVM–>机器码

(1)类加载时机

虚拟机规范中严格规定6种情况必须立即对类加载并初始化:

  • 创建对象实例,new对象的时候,会对类初始化,前提是类没有被初始化过
  • 通过class文件反射创建对象
  • 调用类的静态属性或给静态属性赋值 XXXX.instance
  • 调用类的静态方法
  • 虚拟机启动时被标识为启动的类:比如main方法所在类
  • 初始化一个类的子类,使用子类的时候需要先初始化父类
    注: Java的类加载是动态的,并不会一次性将所有的类全部加载后再执行,保证程序运行的基本类完全加载JVM中,至于其他类,在需要时再加载,可以节省内存
    不会被加载的情况:
  • 在同一个类加载器下面一个类只会被初始化一次,如果已经被初始化了就不必再被初始化
  • 在编译时能确定下来的静态变量,不会对类进行初始化,比如final修饰的静态变量
(2)类加载器

作用:负责将字节码加载到内存
JVM中提供了3种类加载器:

  • BootStrap ClassLoader:负责加载jre/lib/rt.jar里所有的class,由C++实现的,不是ClassLoader的子类
  • Extension ClassLoader:负责加载扩展功能的jar包,指jre/lib/*.jar或者-Djava.ext.dirs指定目录下的jar
  • Application ClassLoader:负责加载classpath中指定的jar及目录中的class
(3)双亲委派模型

在这里插入图片描述
双亲委派模型的工作过程如下:
1、当前类加载器从自己已经加载的类中查询是否此类已经加载,如果已经加载则返回原来已经加载的类。
2、如果没有找到,就去委托父类加载器去加载。父类加载器也会采用同样的策略,查看自己已经加载过的类中是否包含这个类,有就返回,没有就委托其父类去加载,直到委托到启动类加载器为止。因为如果父类加载器为空了,就代表使用启动类加载器作为父加载器去加载该类。(也就是看到的String类加载器为null)
3、如果启动类加载器加载失败,就会使用扩展类加载器来尝试加载,继续失败则会使用AppClassLoader来加载,继续失败就会抛出一个异常ClassNotFoundException。
双亲委派优势:
1、避免类的重复加载
2、安全性,避免用户自己编写的类动态的替换Java的核心类。

类加载过程

类被加载到内存开始到卸载出内存,整个生命周期分为7个阶段:
加载、验证、准备、解析、初始化、使用、卸载
在这里插入图片描述

  • 加载: 在加载阶段,虚拟机需要完成3件事
    1、通过一个类的权限命名获取定义此类的二进制文件
    2、将加载的二进制文件存储在方法区
    3、在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口

  • 连接: 连接阶段分为三部分:验证、准备、解析
    1、验证:为了确保class文件的字节流中包含的信息符合虚拟机的要求,保证加载字节码文件不会危害虚拟机的安全,验证包括:文件格式验证、元数据验证、字节码验证、符号引用验证
    2、准备:主要为static类型的变量分配内存并设置初始值,变量所使用的内存在方法区分配
    赋初始值:基本的引用类型, 0,0l,false,自定义的引用类型:null
    3、解析:将符号引用替换为直接引用 ,主要针对类或者接口,字段、方法,等
    符号引用:可以理解就是字符串,比如引用一个类,java.util.ArraList这个就是一个符号引用,符号引用不一定被加载到内存
    直接引用:指针后者地址偏移量,引用对象一定存在在内存(已经被加载)
    4、初始化:主要工作是对静态变量赋值设定初始值
    执行静态代码块

static int i= 10;
在准备阶段为i分配空间,给定默认值0
初始化阶段将i=10进行赋值

类加载使用实例:单例模式----在一个JVM实例中只存在一个对象实例
单例实现要点:
1、将类的构造函数私有化
2、提供一个public方法获取当前对象实例

public class Single{
   private static final Single s = new Single();
   private Single(){}
   public Static Single getInstance(){
      return s;
   } 
}

//调用
Single.getInstance();

1、当前代码是否满足单例
2、解释原因

可以满足单例
当调用Single.getInstance()方法时,如果第一次使用该类,按照类的加载时机,当前Single类会被加载并完成连接初始化等节点,其中s变量是一个静态变量,这在准备及初始化的阶段就会对静态变量做分配内存及赋值等过程,而JVM加载机制保证了一个类只会被加载一次,及s的分配内存及赋值的过程只会在加载时被处理一次,因此该单例是符合要求的,单例的实现是由JVM的类加载机制保证的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java虚拟机(JVM)内存模型是JVM用于管理Java程序运行时内存的一种机制。JVM将内存划分为不同的区域,每个区域都有自己的用途和生命周期。这些区域包括: 1. 程序计数器(Program Counter Register):程序计数器是一块较小的内存区域,它用于记录当前线程所执行的字节码指令的地址。每个线程都有一个独立的程序计数器。 2. Java虚拟机栈(Java Virtual Machine Stacks):Java虚拟机栈是线程私有的,它用于存储Java方法执行时的局部变量、操作数栈、动态链接、方法出口等信息。 3. 本地方法栈(Native Method Stack):本地方法栈与Java虚拟机栈类似,但是它是为本地方法服务的。 4. Java堆(Java Heap):Java堆是Java虚拟机管理的内存中最大的一块。Java对象实例和数组都在堆上分配内存。堆是所有线程共享的一块内存区域。 5. 方法区(Method Area):方法区是用于存储已被JVM加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。 6. 运行时常量池(Runtime Constant Pool):运行时常量池是方法区的一部分,用于存放编译器生成的字面量和符号引用。 7. 直接内存(Direct Memory):直接内存不是JVM运行时数据区的一部分,但是它也可以被JVM所管理。在使用NIO(New IO)时,可以使用直接内存来提高IO性能。 以上就是JVM内存模型的主要区域。JVM内存模型的划分对于Java程序的运行和调优都非常重要。在实际开发中,需要根据具体情况调整JVM内存的配置,以达到更好的性能表现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值