15158846557 在线咨询 在线咨询
15158846557 在线咨询
所在位置: 首页 > 营销资讯 > 网站运营 > 深入了解Java虚拟机(JVM)

深入了解Java虚拟机(JVM)

时间:2023-07-01 02:21:01 | 来源:网站运营

时间:2023-07-01 02:21:01 来源:网站运营

深入了解Java虚拟机(JVM):

什么是JVM?

JVM是JRE的一部分。它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。JVM有自己完善的硬件架构,如处理器、堆栈、寄存器等,还具有相应的指令系统。Java语言最重要的特点就是跨平台运行。使用JVM就是为了支持与操作系统无关,实现跨平台。所以,JAVA虚拟机JVM是属于JRE的,而现在我们安装JDK时也附带安装了JRE(当然也可以单独安装JRE)。

JVM在执行字节码时,实际上最终还是把字节码解释成具体平台上的机器指令执行。




JDK,JVM,JRE三者之间的联系

JVM就是我们常说的java虚拟机,它是整个java实现跨平台的 最核心的部分,所有的java程序会首先被编译为.class的类文件,这种类文件可 以在虚拟机上执行,也就是说class并不直接与机器的操作系统相对应,而是经过虚拟机间接与操作系统交互,由虚拟机将程序解 释给本地系统执行。

JRE是指java运行环境。光有JVM还不能成class的 执行,因为在解释class的时候JVM需要调用解释所需要的类库lib。 在JDK的安装目 录里你可以找到jre目录,里面有两个文件夹bin和lib,在 这里可以认为bin里的就是jvm,lib中则是jvm工 作所需要的类库,而jvm和 lib和起来就称为jre。

JDK是java开发工具包,开发者用来编译和调试,基本上每个学java的人都会先在机器 上装一个JDK,那他都包含哪几部分呢?让我们看一下JDK的安装目录。在目录下面有 六个文件夹、一个src类库源码压缩包、和其他几个声明文件。其中,真正在运行java时起作用的 是以下四个文件夹:bin、include、lib、 jre。现在我们可以看出这样一个关系,JDK包含JRE,而JRE包 含JVM。




JVM执行程序的过程

1) 加载.class文件

2) 管理并分配内存

3) 执行垃圾收集

JRE(java运行时环境)由JVM构造的java程序的运行环,也是Java程序运行的环境,但是他同时一个操作系统的一个应用程序一个进程,

因此他也有他自己的运行的生命周期,也有自己的代码和数据空间。

JVM在整个jdk中处于最底层,负责于操作系统的交互,用来屏蔽操作系统环境,

提供一个完整的Java运行环境,因此也就虚拟计算机。




JVM的生命周期

1) JVM实例对应了一个独立运行的java程序它是进程级别

a) 启动。启动一个Java程序时,一个JVM实例就产生了,任何一个拥有public static void

main(String[] args)函数的class都可以作为JVM实例运行的起点

b) 运行。main()作为该程序初始线程的起点,任何其他线程均由该线程启动。JVM内部有两种线程:守护线程和非守护线程,main()属于非守护线程,守护线程通常由JVM自己使用,java程序也可以表明自己创建的线程是守护线程

c) 消亡。当程序中的所有非守护线程都终止时,JVM才退出;若安全管理器允许,程序也可以使用Runtime类或者System.exit()来退出

2) JVM执行引擎实例则对应了属于用户运行程序的线程它是线程级别的




Java执行过程以及JVM内存模型

可以看到java的执行过程。

至于类加载器,这里我们先不做过多的介绍,在后续博客中更新。

运行时数据区,即JVM的内存模型

方法区和堆是线程共享,程序计数器、虚拟机栈、本地方法栈是线程私有的

这一块比较重要,接下来详细介绍一下运行时数据区:

程序计数器(PC寄存器)

    由于在JVM中,多线程是通过线程轮流切换来获得CPU执行时间的,因此,在任一具体时刻,一个CPU的内核只会执行一条线程中的指令,

  因此,为了能够使得每个线程都在线程切换后能够恢复在切 换 之前的程序执行位置,每个线程都需要有自己独立的程序计数器,并且不能互相被干扰,

  否则就会影响到程序的正常执行次序。因此,可以这么说,程序计数器是每个线程所私有的。由于程序计数器中存储的数据所占空间的大小不会随程序的执行而发生改变,

  因此,对于程序计数器是不会发生内存溢出现象(OutOfMemory)的。




虚拟机栈(VM Stack)

线程私有它的生命周期和线程相同

JVM的栈中存放的数据主要有:

1.各种基础数据类型(boolean、byte、char 、short、int、float、long、double );

2.方法的形式参数,方法调用完后从栈空间回收;

3.引用对象的地址,引用完后,栈空间地址立即被回收,堆空间等待GC。

JVM的栈也属于线程私有的内存,用户可以设置大小。对于异常,这块区域有两种情况:如果线程请求的栈深度大于JVM所允许的深度,将抛出StackOverflowError异常;如果JVM的栈可以动态扩展,但是在尝试扩展时无法申请到足够的内存则抛出OutOfMemoryError异常。




本地方法栈

Java本地方法(Native Method)是由其它语言编写的,编译成和处理器相关的机器代码,保存在动态链接库中,即.dll(windows系统)文件中,格式是各个平台专有的。虽说Java方法是与平台无关的,但是本地方法不是。程序运行中Java方法调用本地方法时,JVM装载包含这个本地方法的动态库的,并调用这个方法。通过本地方法,Java程序可以直接访问底层操作系统的资源,如果你这样用,你的程序就变成平台相关了,因为本地方法的动态库是与平台相关的,但是使用本地方法还可能把程序变得和特定的Java平台实现相关。

本地方法栈与虚拟机栈作用类似,Sun HotSpot中直接将本地方法栈和虚拟机栈合二为一,它和虚拟机栈一样都会抛出StackOverflowError和OutOfMemoryError异常。






Java中的堆是用来存储对象本身的以及数组(数组引用是存放在Java栈中的)。堆是被所有线程共享的,在JVM中只有一个堆。

Java 堆是JVM所管理的内存中最大的一块并且是所有线程共享的内存区域,在JVM启动时创建。堆存放的就是存放对象实例和数组,几乎所有的对象实例都在这里分配内存。Java堆是垃圾回收器管理的主要区域,如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError 异常




方法区

方法区是各个内存所共享的内存空间, 方法区中主要存放被JVM加载的类信息、常量、静态变量、即时编译后的代码等数据。方法区的大小用户可以更改,如果发生溢出会出现java.lang.OutOfMemoryError:PermGen space信息。

在方法区中有一个非常重要的部分就是运行时常量池,它是每一个类或接口的常量池的运行时表示形式,在类和接口被加载到JVM后,

 对应的运行时常量池就被创建出来。当然并非Class文件常量池中的内容才能进入运行时常量池,在运行期间也可将新的常量放入运行时常量池中,比如String的intern方法。




直接内存

直接内存并不是虚拟机运行时数据区的一部分,也不是JVM规范中定义的内存区域,但是这部分内存也被频繁地使用,而且也可能导致OutOfMemoryError 异常出现。

为了提高IO速度,在JDK 1.4 中新加入了NIO(New Input/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O 方式,它可以使用Native 函数库直接分配堆外内存,然后通过一个存储在Java 堆里面的DirectByteBuffer 对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在Java 堆和Native 堆中来回复制数据。显然,本机直接内存的分配不会受到Java 堆大小的限制,但是,既然是内存,则肯定还是会受到本机总内存(包括RAM 及SWAP 区或者分页文件)的大小及处理器寻址空间的限制。服务器管理员配置虚拟机参数时,一般会根据实际内存设置-Xmx等参数信息,但经常会忽略掉直接内存,使得各个内存区域的总和大于物理内存限制(包括物理上的和操作系统级的限制),从而导致动态扩展时出现OutOfMemoryError异常。




总结:JVM内存溢出的情况





















关键词:虚拟,深入

74
73
25
news

版权所有© 亿企邦 1997-2025 保留一切法律许可权利。

为了最佳展示效果,本站不支持IE9及以下版本的浏览器,建议您使用谷歌Chrome浏览器。 点击下载Chrome浏览器
关闭