1.JVM中的五大内存区域划分详解及快速扫盲

本博客参考《深入明白Java虚拟机》这本书
视频及电子书详见:https://shimo.im/docs/HP6qqHx38xCJwcv9/

一、快速扫盲

1. JVM是什么

  JVM是Java Virtual Machine的缩写,即咱们经常提到的Java虚拟机。虚拟机是一种抽象化的计算机,有着自己完善的硬件架构,如处理器、客栈等,详细有什么咱们不做领会。现在我们只需要知道想要运行Java文件,必须先通过一个叫javac的编译器,将代码编译成class文件,然后通过JVM把class文件注释成各个平台可以识别的机械码,最终实现跨平台运行代码。
.JVM中的五大内存区域划分详解及快速扫盲"

2. JDK、JRE、JVM之间的关系

  • JDK:全称为Java Development Kit,汉语为java开发工具包,即所有有关java的东西都包罗在里面,好比运行环境JRE、java的焦点代码、JVM等等。
  • JRE:全称为Java Runtime Environment,汉语为java运行环境,即想要运行java文件必须先有java的环境才行,jre就是提供了这么一个环境。
  • JVM:上面已经提到了JVM,它是java最焦点的部门。
    简单用一张图来明白这三个的关系:
    .JVM中的五大内存区域划分详解及快速扫盲"

3. jvm的组成身分

.JVM中的五大内存区域划分详解及快速扫盲"
  不领会jvm的同砚看到这张图后可能会有点懵逼,不外没关系,放这张图只是想让你领会jvm中有三块内容异常重要,1.java代码若何执行?2.内存若何治理?3.线程资源若何行使?脑壳里有个印象即可,带着问题去学习。

4. 运行java文件的也许流程

  想要运行java的源文件,必须要经由javac编译器编译成.class文件,也就是字节码文件。然后通过jvm中的注释器,注释成特定机械上的机械码。每种机械上的注释器是不一样的,我们经常用的也就是windows和linux系统,这也是为什么java能够跨平台的缘故原由。当一个程序从最先运行,虚拟机就最先实例化,多个程序运行就会存在多个虚拟机实例,程序退出或者关闭,虚拟机实例也将随之消亡,多个虚拟机之间的数据是不共享的。

二、JVM运行时数据区

1. 运行时数据区域组成

  虚拟机在执行java程序时,会将自己治理的内存划分为几个区域,每个区域都有自己的用途,而且建立时间和销毁时间也不一样。在程序运行时的内存区域主要可以划分为五个,分别是:方式区、堆、虚拟机栈、内陆方式栈、程序计数器。可以用下面的图来形貌:
.JVM中的五大内存区域划分详解及快速扫盲"

2. Java堆

  Java堆是java虚拟机所治理的内存中最大的一块,是被所有线程都共享的内存区域。存在的唯一目的就是存放工具实例,险些所有的工具实例都在这里举行分配内存。不外现在随着手艺的不断发展,也并不是所有的工具实例都在堆中分配内存,可能也存在栈上分配。由于所占空间大,又存放种种实例工具,因此java虚拟机的垃圾接纳机制主要治理的就是此区域,详细的垃圾接纳方式以后会提到。JVM规范中划定堆可以处于物理上不延续的内存空间中,只要逻辑上是延续的即可。而且可以通过-Xmx和-Xms来扩展堆的内存巨细,若是在堆中没有足够的内存为实例分配,而且堆也无法在扩展时,就会报OutOfMemoryError异常。

浅析Redis分布式锁—从自己实现到Redisson的实现

3 方式区

跟Java堆一样,方式区是各个线程共享的内存区域,此区域是用来存储类的信息(类的名称、字段信息、方式信息)、静态变量、常量以及编译器编译后的代码。JVM规范中并不区分方式区和堆,只把方式区形貌为堆的逻辑部门,然则它却有一个别名叫做非堆(Non-Heap),目的就是与Java堆区离开。凭据垃圾接纳机制中分代接纳的头脑,若是在HotSpot虚拟机上开发,可以把方式区称为“永远代”(只是可以这么明白,但实质是不一样的),垃圾接纳机制在Java堆中划分一个部门称为永远代,用此区域来实现方式区,这样HotSpot的垃圾收集器就可以像治理Java堆一样治理这部门内存,而不必为方式区开发专门的内存治理器。

运行时常量池

运行时常量池是方式区的一个部门,class文件中除了有类的版本、字段、方式、接口等形貌信息外,另有一项信息是常量池,用于存放编译时代天生的种种字面量和符号引用,这部门内容会在类加载后进入方式区的运行时常量池中。Java 虚拟机对 Class 文件的每一部门(自然也包罗常量池)的花样都有严酷的划定,每一个字节用于存储哪种数据都必须相符规范上的要求,这样才会被虚拟机认可、装载和执行。

4. 程序计数器

虽然在上图中程序计数器的面积很大,但实际上它是一块较小的内存空间,可以看做当前线程所执行字节码的行号指示器。字节码注释器在工作中时下一步该干啥、到哪了,就是通过它来确定的。人人都知道在多线程的情形下,CPU在执行线程时是通过轮流切换线程实现的,也就是说一个CPU处理器(假设是单核)都只会执行一条线程中的指令,因此为了线程切换后能恢复到准确的执行位置,每个线程都要有一个自力的程序计数器,各条线程之间的计数器互不影响,自力存储,我们称这类内存区域为“线程私有”的内存。很明显,程序计数器就是线程私有的。若是线程正在执行的是一个java方式,程序计数器纪录的是正在执行的虚拟机字节码指令地址;若是执行的Native方式,程序计数器纪录的值为空(Undefined),此内存区域是java中唯一一个在java虚拟机规范中没有划定任何OutOfMemoryError情形的区域。

5. Java虚拟机栈

我们经常会把java内存粗拙的分为两个部门,堆和栈,Java虚拟机栈就是栈这一部门,或者说是虚拟机栈中局部变量表部门。跟程序计数器一样,虚拟机栈也是线程私有的,它的生命周期跟线程相同。每个方式在执行的同时都市建立一个栈帧(Stack Frame),每个栈帧对应一个被挪用的方式,栈帧中用于存储局部变量表、操作数栈、动态链表、方式出口等信息。每一个方式从最先执行到竣事就对应着一个栈帧在虚拟机栈中从入栈到出栈的历程。

  • 局部变量表:顾名思义,他就是用来存储方式中的局部变量(包罗在方式中生命的非静态变量以及函数形参),对于基本数据类型,直接存值,对于引用类型的变量,存储指向该工具的引用。由于它只存放基本数据类型的变量、引用类型的地址和返回值的地址,这些类型所需空间巨细已知且牢固,以是当进入一个方式时,这个方式需要在栈帧中分配多大的局部变量空间是完全可以确定的,在方式运行时代也不会改变局部变量表的巨细。
  • 指向运行常量池的引用:在方式执行历程中难免会使用到类中界说的常量,因此栈帧中要存放一个指向运行时常量池的引用。
  • 方式返回地址:当一个方式执行竣事后,要返回到之前挪用它的地方,因此在栈帧中需要保留一个方式返回地址。

6. 内陆方式栈

内陆方式栈与虚拟机栈的功效异常的相似,区别不外是虚拟机栈为虚拟机执行java方式服务,而内陆方式栈为虚拟机执行Native方式服务。有的虚拟机并不会区分内陆方式栈和虚拟机栈,好比Sun HotSpot虚拟机直接将两个合二为一。

7. 用一张图总结

.JVM中的五大内存区域划分详解及快速扫盲"

原创文章,作者:admin,如若转载,请注明出处:https://www.2lxm.com/archives/1876.html