JVM内存区域划分
本章要点
- JVM内存区域组成和内存区域划分后不同区域的功能
- JVM类加载机制和类加载流程
- 双亲委派模型
- JVM中的垃圾回收机制(GC)
JVM执行流程
我们知道JVM就我们的java虚拟机(Java Virtual Machine)的简称!
java执行一个java文件的流程:
程序在执行之前先要把java代码转换成字节码(class文件),JVM 首先需要把字节码通过一定的方式类加载器(ClassLoader) 把文件加载到内存中 运行时数据区(Runtime Data Area) ,而字节码文件是 JVM 的一套指令集规范,并不能直接交个底层操作系统去执行,因此需要特定的命令解析器 执
行引擎(Execution Engine)将字节码翻译成底层系统指令再交由CPU去执行,而这个过程中需要调用其他语言的接口 本地库接口(Native Interface) 来实现整个程序的功能,这就是这4个主要组成部分的职责与功能。
JVM大致通过4个部分来执行我们的java程序:
- 类加载器
- 运行时数据区
- 执行引擎
- 本地库接口
而上述4个部分中我们的java运行时数据区也叫内存布局,我们重点了解一些这块空间的内存是如何布局的即可!
内存区域划分
为啥要将内存区域进行划分呢?
对内存区域进行划分,就让不同的内存空间具有不同的功能,就好比我们的学校不同区域具有不同的功能,教学楼是用来学习的,寝室是用来睡觉的,食堂是用来吃饭的!
而我们的JVM中的内存区域也是按照不同区域行使的功能进行了划分!
java运行时数据区(内存布局划分如下)
主要分为4个重要的区域
- 程序计数器
- 栈
- 堆
- 方法区
我们下面来分别介绍这个4个不同区域的功能
程序计数器
程序计数器这块空间保存了下一条要执行指令的地址,我们通过这个地址空间,就可以让程序顺利执行下去!
这里的程序计数器每个线程都有一个,我们知道线程是程序调度的基本单位嘛!
而我们的CUP是需要并发执行的,并不能保证某一时刻连贯的就把某一进程执行结束,我们的CPU需要服务于多个线程,所有程序计数器很好的对程序的执行的位置进行了存档,当我们的该线程再次被CPU调用时根据程序计数器中记录的指令就可以找到上次执行的位置继续执行程序!
栈
这里的栈和我们数据结构中的栈结构类似,不过这里的栈保存的信息是
栈帧
栈中主要保存2种信息
- 方法调用信息
- 局部变量
栈帧(方法调用信息):
方法的实参
局部变量
方法调用的位置
方法执行结束的位置
我们通过下面代码进一步了解:
public class Main {
static void fun1(){
fun2();
}
static void fun2(){
fun3();
}
static void fun3(){
fun4();
}
static void fun4(){
System.out.println("fun4");
}
public static void main(String[] args) {
fun1();
}
}
当我们需要执行
fun1
方法,首先我们需要将main
栈帧入栈,通过main
栈帧中的信息,我们可以知道此时我们需要调用fun1
,然后就将fun1
栈帧入栈,紧接着fun3
入栈,最后调用fun4
然后进行打印,当我们的fun4
方法调用结束,此时fun4
栈帧就会出栈,然后回到fun3
调用位置,fun3
结束,fun3
出栈,回到fun2
,fun2
出栈,fun1
,main
栈帧出栈,整个程序就执行结束了!
这里就需要注意的是我们的栈空间有限,一般只有几M到十几M大小,虽然可以自行设置,但是当我们递归时如果递归次数过多,或者递归出口没有设置很有可能导致栈溢出StackOverflow
堆(线程共享)
- 成员变量
new
出来的对象
class A{
public String name1 = "张三";
public void fun(){
String name2 = new("李四");
System.out.println(name2);
}
}
我们的上述代码中成员变量 name1
保存在堆中,fun
方法中的name2
引用属于局部变量保存在栈中,而其引用指向的本体new("李四")
对象本体保存在堆!
注意:
这里的堆空间是线程共享空间,一个进程只要一个堆空间,所有这里的堆空间大小最大!
方法区
方法区存放的是类对象
啥是类对象呢?
我们
JVM
执行一个.java
程序,第一步要先将这个通过javac
指令将该文件转成二进制字节码文件.class
,而.class
文件就会来到内存中,通过JVM
加载将其构造成类对象,这里的加载过程就叫做类加载!
类对象都有些啥呢?
类对象就是描述这个类长啥样!
类名,有哪些成员,成员名,成员类型,public/private,方法,方法名,方法中的指令…
类对象中还有一个重要东西,静态成员~
就是static
修饰的成员雷属性,而普通的成员叫做实例属性!
上面就是对内存区域划分及其功能的大致介绍,指的注意的是不同版本的JVM可能有不同的划分方式,但是大致都是一样的!
- 点赞
- 收藏
- 关注作者
评论(0)