Java底层知识JVM详解

文章探讨的是关于JVM的底层架构,包括内存模型,调优等等…

1. 平台无关性

Java程序在运行时,会经历两个过程:编译与运行。编译时,IDE在保存java程序时会直接编译好程序,你只需直接运行就行,如果想要查看具体的编译文件,可以在CMD模式或者在IDEA环境下进行反编译(Javap)编译过后的.Class文件。
在这里插入图片描述
Java源码首先被编译成字节码,再由不同平台的JVM进行解析,Java语言在不同的平台上运行时不需要进行重新编译,Java虚拟机在执行字节码的时候,把字节码转换成具体平台上的机器指令。

2. JVM如何加载.class文件

JVM的具体架构:
在这里插入图片描述

  • Class Loader:依据特定的格式,加载class文件到内存。
  • Execution Engine:对命令进行解析。
  • Native Interface:融合不同开发语言的原生库为Java所用。
  • Runtime Date Area:JVM开辟的内存空间。

3. 反射

反射就是把Java类中的属性或方法映射为Java对象,不管是私有(公有)属性/方法,对于任意一个对象,都能狗调用它的任意的方法或属性,这栋动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。
如何获取一个类?
第一步:
用Class类的forName方法,必须用全路径,例如:
在这里插入图片描述
第二步:
用newInstance方法创建类的实例
在这里插入图片描述
获取方法的声明:
Method 方法名=获取类的名字.getDeclareMethod(类是方法名,参数类型.class);
方法名.setAccessible(true);
在这里插入图片描述
获取Public方法:
在这里插入图片描述

4. ClassLoader

ClassLoader工作在Class装载的加载阶段,器主要作用是从系统外部获得Class二进制数据流。它是Java的核心组件,所有的Class都是有ClassLoader进行加载的,ClassLoader负责通过将class文件里的二进制数据流装载进系统,然后交给Java虚拟机进行连接、初始化等操作。

Bootstrap ClassLoader/启动类加载器
主要负责jdk_home/lib目录下的核心 api 或 -Xbootclasspath 选项指定的jar包装入工作,用C++编写

Extension ClassLoader/扩展类加载器
主要负责jdk_home/lib/ext目录下的jar包或 -Djava.ext.dirs 指定目录下的jar包装入工作

App ClassLoader/系统类加载器
主要负责java -classpath/-Djava.class.path所指的目录下的类与jar包装入工作

Custom ClassLoader/用户自定义类加载器(java.lang.ClassLoader的子类)
用户自定义类加载器,必须继承自java.lang.ClassLoader

自定义ClassLoader的实现:
关键函数:
在这里插入图片描述

5. 类加载器的双亲委派机制

在这里插入图片描述
为什么要使用双亲委派机制?

  • 避免多份同样字节码的加载

6. LoadClass和forName的区别

类的加载过程
在这里插入图片描述

  • Class.forName得到的Class是已经初始化完成的
    在这里插入图片描述
  • ClassLoader.loadClass得到的class是还没有链接的,没有初始化完成的,多用于SpringMVC
    在这里插入图片描述

7. Java内存模型

在这里插入图片描述
Java程序运行在IDE上面,需要内存空间,就需要划分内存。以JDK8举例:
JVM内存模型:
在这里插入图片描述

线程私有:

程序计数器(Program Counter Register):

当前线程所执行的字节码行号指示器(逻辑)
改变计数器的值来选取下一条需要执行的字节码指令(循环、分支、跳转等等)
和线程是一对一的关系即“线程私有”
对Java方法计数,如果是Native方法则计数器值为Undefined
不会发生内存泄露

Java虚拟机栈(Stack):

Java方法执行的内存模型
包含多个栈帧

栈帧示意图:

在这里插入图片描述
栈帧用于存储局部变量表,对应了各个方法的入栈出栈的过程,Java虚拟机栈用于存储栈帧,当方法调用结束时,帧才会被销毁。

局部变量表和操作数栈
局部变量表:包含方法执行过程中的所用变量
操作数栈:入栈,出栈,复制,交换等等操作

本地方法栈:主要用于标注Native方法

线程共享:

线程共享包含元空间(MetaSpace)和永久代(PermGen)

元空间使用本地内存,永久代使用JVM的内存

元空间的优势:
字符串常量池存在永久代中,容易出现性能问题和内存溢出
类和方法的信息大小难易确定,给永久代的大小指定带来困难
永久代会为GC带来不必要的复杂性

Java堆(Heap):

对象实例的分配区域
在这里插入图片描述
GC管理的主要区域
在这里插入图片描述

JVM调优:

参数实例:
在这里插入图片描述
-Xss:规定了每个线程虚拟机栈(堆栈)的大小
-Xms:堆的初始值
-Xmx:堆能达到的最大值

Java内存模型中堆和栈的区别-内存分配策略:

静态存储:编译时确定每个数据目标在运行时的存储空间需求
栈式存储:数据区需求在编译时未知,运行时模块入口确定
堆式存储:编译时或运行时模块入口都无法确定,动态分配

管理方式:栈自动释放,堆需要GC
空间大小:栈比堆小
碎片相关:栈产生的碎片小于堆
分配方式:栈支持静态和动态分配,而堆仅支持动态分配
效率:栈的效率比堆高

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值