当前位置:网站首页 > Java基础 > 正文

java基础知识讲解2



文章目录

  • JVM基础知识:
  • 1、Java跨平台性解释
  • 2、JVM介绍
  • 3、JDK/JVM/JRE 三者关系
  • 4、JVM 的生命周期
  • JVM的工作过程:
  • 类加载机制:
  • 1、 类加载的时机:
  • 2、类加载过程
  • Java内存模型
  • 1、程序计数器
  • 2、虚拟机栈
  • 3、本地方法栈
  • 4、堆
  • 5、方法区
  • JVM启动参数的设置
  • 1、标准参数
  • 2、非标准参数
  • 3、非静态参数

JVM基础知识:

1、Java跨平台性解释

JVM是用C/C++开发的,是编译后的机器码,不能跨平台,,不同的平台下需要安装不同版本的JVM,我们编写的Java源码,编译后会生成一种字节码文件(.class)JVM就是负责将字节码文件翻译成特定平台下的机器码然后运行。所以我们只需要在不同的平台上安装相应版本的JVM,就可以运行Java程序了,即实现了“一次编译,到处运行”的目的

2、JVM介绍

JVM指的就是 Java Virtual Machine,即Java虚拟机。JVM是Java的核心和基础,是Java编译器和OS平台之间的虚拟处理器,它是一种利用软件方法实现的抽象的计算机基于下层的操作系统和硬件平台,可以在上面执行Java的字节码文件。JVM有自己完善的硬件架构,如:处理器、堆栈、寄存器等,还有相应的指令系统,Java语言大的特点就是跨平台运行,使用JVM就是为了跨平台。

3、JDK/JVM/JRE 三者关系

JRE(Java Runtime Environment),Java运行环境,也就是Java平台。任意一个Java程序都必须得在JRE下才能运行。普通的用户只需要运行已经开发好的Java程序时,那么只安装JRE就可以了。
JDK(Java Development Kit)是程序开发者用来编译、调试Java程序用到的开发工具包。JDK的工具也是Java程序,也得安装JRE后才能运行。为了维护JDK的独立性和完整性,JRE的安装也是JDK的安装的一部分内容。所以,在JDK的安装目录下,我们可以看到一个名为JRE的目录,它是就用于存放JRE文件的。
JVM(Java Virtual Machine) Java虚拟机是JRE的一java基础知识讲解2部分,它是一个虚拟的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。

4、JVM 的生命周期

启动和消亡:
JVM负责运行一个Java程序,当一个Java程序启动时,一个虚拟机实例也随之诞生,当该Java程序关闭退出时,这个虚拟机实例也就随之消亡。

JVM运行起点:
Java虚拟机实例通过调用某个初始类的main()方法来运行一个Java程序,这个main()方法的修饰符必须是public(公有的)、static(静态的)、void(无返回值)、并且只允许一个字符转数组作为参数(String[] args)。任何拥有这样一个main()方法的类都可以作为Java程序运行的起点。

JVM的两种线程:
守护线程:守护线程通常是由虚拟机自己使用的,比如执行垃圾收集的线程。但是Java程序也可以把创建的线程标记为守护线程
非守护线程:Java程序中的初始线程——main() 的线程就是非守护线程。只要还有任何非守护线程在运行,那么这个Java程序也在继续运行。当该程序中所有的非守护线程都终止时,虚拟机实例将自动退出。如果安全管理器允许的话,程序本身也能够通过调用Runtime类或者System类中的exit()方法来退出。

JVM的工作过程:

类加载机制:

1、 类加载的时机:

虚拟机规范严格规定了有且只有5种情况必须立即对类进行初始化,也就是将class文件加载到JVM中
主动初始化的6种方式(前提是这个类没有被初始化过):
①:创建对象实例:new对象的时候,会对类初始化(最常用)
②:调用类的静态属性或为静态属性赋值
③:调用类的静态方法
④:通过class文件反射创建对象
⑤:初始化一个子类:使用子类的时候先初始化父类
⑥:Java虚拟机启动时被标记为启动类的类:例如main()方法所在的类

注意:Java的类的加载是动态的,他并不会一次性把所有的类都加载完以后才运行,而是保证程序运行的基础类完全加载到JVM中,而其它类则是在需要的时候才会加载,这么做是为了节省内存开销

不会进行类初始化的情况
①:在同一个类加载器下面只能初始化类一次,如果已经完成了初始化就不会再被初始化了
②:在编译的时候,能确定下来的静态变量(编译常量,比如final修饰的静态变量),不会对类进行初始化

2、类加载过程

负责将字节码文件加载到内存

类加载器

java jvm讲解 jvm基础知识_Java

BootStrap ClassLoader(启动类加载器):
这是负责加载$JAVA_HOME中 jre/lib/rt.jar 里所有的class,是由C++实现的顶级类加载器,不是 ClassLoader的子类

Extension ClassLoader(扩展类加载器):
负责加载JAVA 平台中扩展功能的一些jar包,包括 $JAVA_HOME 中 jre/lib/*.jar 或 -Djava.ext,dirs 指定目录下的jar包

App ClassLoader(应用类加载器):
负责加载classpath 中指定的jar 包及目录中的class

双亲委派模型
工作过程:
1、当前类加载器从自己已经加载的类中查询此类是否已经加载,如果已经加载则返回原来已经加载的类
2、如果没有找到则去委托父类加载器加载,父类加载器与之采用同样的策略,查看自己已经加载的类中是否包含这个类,如果包含则返回这个类,如果没有就继续委托它的父类加载器去加载,直到委托到 Bootstrap ClassLoader(启动类加载器)为止。因为父类加载器空了,就代表使用启动类加载器作为父加载器去加载该类
3、如果启动类加载器加载失败,就会使用扩展类加载器尝试加载,继续失败则尝试使用App ClassLoader 来加载,继续失败就会抛出一个 ClassNotFoundExpectation

使用双亲委派模型的好处:
1、安全性,可以避免用户自己编写的类动态的替换掉Java的一些核心类。如果不采用双亲委派模型的加载方式来进行类的加载,那我们就可以随时使用自定义的类来动态的替换掉 Java 核心 API 中定义的类。如果黑客将 “病毒代码” 写入他们自定义的String类中,当类加载器将自定义的String 类加载到 JVM 上时,就会使 JVM 遭受病毒的攻击。而使用双亲委派模型则可以避免这种情况,因为 String 类在启动时就已经被加载过了
2、避免类的重复加载,由于 JVM 判断两个类是否相同时,不仅根据类名去判断,还得根据加载他们的类加载器是否相同去判断,相同的class文件被不同的类加载器加载后得到的结果就是不同的类

类加载的详细过程

java jvm讲解 jvm基础知识_加载_02

加载,查找并加载类的二进制数据,在Java堆中也创建一个java.lang.class 对象。
连接,连接又包含三部分的内容: 验证、准备、初始化
①:验证,文件格式、元数据、字节码、符号引用验证
②:准备,为类的静态变量分配内存,并将其初始化为默认值
③:解析,把类中的符号引用转为直接引用
初始化,为类的静态变量赋予正确的初始值

Java内存模型

1、程序计数器

程序计数器是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。字节码解释器工作时通过改变这个计数器的值来选取下一条需要执行的字节码指令。循环、分支、跳转、异常处理、线程回复等功能都需要通过这个计数器来完成。此外,为了线程切换后能回到正确的执行位置,每条线程都需要一个独立的程序计数器,各线程计数器之间互不影响,独立存储,这类内存区域就被称为“线程私有”的内存

主要作用有两个:
①:字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制,如:顺序执行、选择、循环、异常处理
②:在多线程的情况下,程序计数器用于记录当前线程执行的位置,这样就可以在线程被切换回来的时候知道该线程上次运行到哪了

注意:程序计数器是唯一个不会出现 OutOfMemoryError 的内存区域,它的生命周期随着线程的创建而创建,随着线程的结束而消亡

2、虚拟机栈

与程序计数器相同,Java虚拟机栈也是线程私有的,它的生命周期和线程相同,描述的是 Java 方法执行的内存模型。Java内存可以大致分为堆内存(Heap)和栈内存(Stack),其中栈就是现在所说的虚拟机栈,或者说是虚拟机栈中局部变量表部分。实际上,Java虚拟机栈是由一个个栈帧所组成的,而每个栈帧中都拥有:局部变量表、操作数栈、动态链接、方法出口信息。

Java虚拟机栈会抛出两种异常:
StackOverflow:如果 Java 虚拟机栈的内存大小不允许动态扩展,当线程请求栈的深度超过当前 Java 虚拟机栈的最大深度的时候,就会抛出StackOverflow异常
OutOfMemoryError
当Java 虚拟机栈的内存大小允许动态扩展,并且当线程请求栈时内存用完的时候,无法再进行动态扩展了,此时就会抛出OutOfMemoryError异常

3、本地方法栈

与虚拟机栈所发挥的作用类似,区别就是:虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的Native方法服务

4、堆

堆是Java虚拟机所管理的内存里面最大的一块,Java 堆是所有线程所共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例和数组都在Java堆中分配内存。Java 堆是垃圾收集器管理的主要区域,所以它也被称作GC堆(Garbage Collected Heap)

5、方法区

与 Java 堆一样,方法区也是各个线程共享的内存区域,它用于存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。尽管 Java 虚拟机规范将方法区给描述为堆的一个逻辑部分,但它却有一个别名叫作“非堆”(Non-Heap),就是为了与Java堆区分

JVM启动参数的设置

我们学习 Java GC 机制就是为了在实际中去运用,为了在 JVM 出现问题时分析并解决这些问题
在 Java 虚拟机的参数中,有三种表示方法:
①:标准参数(-):所有的 JVM 都必须实现这些参数的功能,而且得向后兼容
②:非标准参数(-X):默认 JVM 实现这些参数的功能,但并不保证所有的 JVM 都满足,并且不保证向后兼容
③:非Stable参数(-XX):此类参数各个 JVM 实现会有所不同,将来可能会随时取消,需要慎重使用

1、标准参数

标准参数是用过 Java 的人较为熟悉的,就是我们在运行 Java 命令时后面加上的参数,如 java -version ,java -jar 等,输入命令 java -help 或 java -?就能获得当前机器所有 Java 的标准参数列表

如果没有指定 -server 或 -client ,JVM启动的时候会自动检测当前主机是否为服务器,如果是就会以 server 模式启动,而64为的 JVM 只有 sever 模式,所以无法使用 -client 参数

JVM 搜索路径的顺序为:
1、先搜索 JVM 自带的 jar 或 zip 包
2、搜索 JRE_HOME/lib/ext 下的 jar 包
3、搜索用户自定义目录

2、非标准参数

非标准参数,是在标准参数的基础上进行扩展的参数,输入“java -X”命令,能够获取当前 JVM 支持的所有非标准参数列表,在不同类型的 JVM 中, 采用的参数有所不同

3、非静态参数

以-XX 表示的非stable参数,JVM中主要的参数可以大致分为三类:

性能参数(Performances Options):用于JVM的性能调优和内存分配控制,初始化内存大小的设置
行为参数(Behavioral Options):用于改变JVM的基础行为,如GC 的方式和算法的选择
调试参数(Debugging Options):用于监控、打印、输出等 JVM 参数,用于显示JVM更加详细的信息

版权声明


相关文章:

  • java学零基础2024-11-08 19:18:02
  • java基础篇第十一版答案2024-11-08 19:18:02
  • java中级基础面试题2024-11-08 19:18:02
  • 成都零基础学习java2024-11-08 19:18:02
  • 实验一 java程序设计基础2024-11-08 19:18:02
  • java基础语法判断年龄大小2024-11-08 19:18:02
  • 东软java基础考试题2024-11-08 19:18:02
  • java9核心基础2024-11-08 19:18:02
  • java基础九九乘法表2024-11-08 19:18:02
  • Java基础面试笔记2024-11-08 19:18:02