1.java程序的执行过程

java源文件->解析器->class文件->java类加载器->java运行时数据区->执行引擎

//gulass.cn/wp-content/uploads/2023/07/1688587258509_0.png

2.我们接下来看一下java运行时数据区

包含程序计数器,虚拟机栈,本地方式栈,方式区,堆,其中程序计数器,虚拟机栈,本地方式区属于指令,方式区和堆属于数据。

一、程序计数器

拿来指示程序执行哪一条指令,这跟汇编语言的程序计数器的功能在逻辑上是一样的。JVM规范中规定,假如线程执行的是非native方式,则程序计数器指向的是当前线程正在执行的字节码指令的地址和行号,假如线程执行的是native方式,则程序计数器中的值undefined。每位线程都有自己独立的程序计数器。为何呢?由于多线程下,一个CPU内核同一时间只会执行一条线程中的指令,因而为了使每位线程在线程切换以后才能恢复到切换之前的程序执行的位置,所以每位线程都有自己独立的程序计数器。

二、Java虚拟机栈(VMStack)

深入理解linux虚拟内存管理_深入理解虚拟内存管理_虚拟内存管理过程

java虚拟机栈中储存的是一个个栈帧,栈是一种数据结构,数据结构是拿来储存数据的,所以虚拟机栈也是拿来储存数据的。储存当前线程运行方式是所须要的数据,指令和返回地址。当程序执行一个方式时,还会创建一个栈帧并压入栈中,执行完毕,则会从栈帧中移除栈。虚拟机栈中有:局部变量表,操作数栈,动态链接,方式出口。

局部变量表:

储存局部变量的表,java的基本的数据类型(boolean、byte、char、short、int、float、long、double),对象的引用(reference类型红帽linux,它不等同于对象本身,可能是一个指向对象起始地址的引用表针,也可能是指向一个代表对象的句柄或其他与此对象相关的位置)和returnAddress类型(指向了一条字节码指令的地址),其中64位宽度的long和double类型的数据会占用2个局部变量空间(Slot),其余的数据类型只占用1个。局部变量表的大小在编译器就可以确定其大小了,因而在程序执行期间局部变量表的大小是不会改变的。在Java虚拟机规范中linux查看磁盘空间,对这个区域规定了两种异常状况:假如线程恳求的栈深度小于虚拟机所容许的深度,将抛出StackOverflowError异常;假如虚拟机栈可以动态扩充(当前大部份的Java虚拟机都可动态扩充,只不过Java虚拟机规范中也容许固定宽度的虚拟机栈),倘若扩充时未能申请到足够的显存,都会抛出OutOfMemoryError异常。

操作数栈:

虚拟机把操作数栈作为它的工作区,程序中的所有估算过程都是在利用于操作数栈来完成的,大多数指令都要从这儿弹出数据,执行运算,之后把结果压回操作数栈。

动态联接:

每位栈帧都包含一个指向运行经常量池中该栈帧所属方式的引用(指向运行经常量池:在方式执行的过程中有可能须要用到类中的常量,持有这个引用是为了支持方式调用过程中的动态联接.

方式返回地址:

当一个方式执行完毕以后,要返回之前调用它的地方,因而在栈帧中必须保存一个方式返回地址。

本地方式栈(NativeMethodStack):

本地方式栈与虚拟机栈所发挥的作用是十分相像的,它们之间的区别不过是虚拟机栈为虚拟机执行Java方式(也就是字节码)服务,而本地方式栈则为虚拟机使用到的Native方式服务。与虚拟机栈一样,本地方式栈区域也会抛出StackOverflowError和OutOfMemoryError异常。

三、方法区(MethodArea):

方式区与Java堆一样,是各个线程共享的显存区域,它用于储存已被虚拟机加载的类信息、常量、静态变量、以及编译器编译后的代码等。运行经常量池(RuntimeConstantPool)是方式区的一部份。Class文件中不仅有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池(ConstantPoolTable),用于储存编译期生成的各类字面量和符号引用,这部份内容将在类加载后步入方式区的运行经常量池中储存。在JVM规范中,没有强制要求方式区必须实现垃圾回收。好多人习惯将方式区称为“永久代”,是由于HotSpot虚拟机以永久代来实现方式区,因而JVM的垃圾搜集器可以像管理堆区一样管理这部份区域,因而不须要专门为这部份设计垃圾回收机制。不过自从JDK7以后,Hotspot虚拟机便将运行经常量池从永久代移不仅。

四、堆(Heap):

在C语言中,程序员可以通过malloc函数和free函数在堆上申请和释放空间。这么在Java中是如何样的呢?Java中的堆是拿来储存对象本身的以及字段(其实,链表引用是储存在Java栈中的),几乎所有的对象实例都在这儿分配显存。在Java中,程序员基本不用去关心空间释放的问题,Java的垃圾回收机制会手动进行处理。另外,堆是被所有线程共享的,在JVM中只有一个堆。

五、内存管理:

JVM将显存界定为6个部份:PC寄存器(也叫程序计数器)、虚拟机栈、堆、方法区、运行经常量池、本地方式栈

java堆:java堆被所有线程共享,堆的主要作用就是储存对象。若果堆空间不够,但扩充时又不能申请到足够的显存时,则抛出OutOfMemoryError异常。

六、垃圾回收机制:

//img4.mukewang.com/5ae6c9650001361f08360465.jpg

(2)、可达性剖析

筹建若干根对象(GCRoot),每位对象都是一个子节点,当一个对象找不到根时,就觉得该对象不可达。

//img4.mukewang.com/5ae6c97500019b5607320642.jpg

3、怎么回收?

(1)、标记——清除算法

遍历所有的GCRoot,分别标记处可达的对象和不可达的对象,之后将不可达的对象回收。

缺点是:效率低、回收得到的空间不连续

(2)、复制算法

将显存分为两块,每次只使用一块。当这一块显存满了,就将还存活的对象复制到另一块上,而且严格依照显存地址排列深入理解linux虚拟内存管理,之后把已使用的那块显存统一回收。

深入理解虚拟内存管理_深入理解linux虚拟内存管理_虚拟内存管理过程

优点是:就能得到连续的显存空间

缺点是:浪费了一半显存

(3)、分代算法

在java中,把显存中的对象按生命长短分为:

//img.mukewang.com/5ae6c97e000189f108280216.jpg

补充:javafinalize()方式:

在被GC回收前深入理解linux虚拟内存管理,可以做一些操作,例如释放资源。有点像析构函数,并且一个对象只能调用一次finalize()方式。

原文出处

本文原创地址://gulass.cn/jyxssjqbhcxj.html编辑:刘遄,审核员:暂无