Java虚拟机的理解与内存模型之间的区别

 2019-12-10 16:00  阅读(907)
文章分类:Java Core

Java虚拟机是干嘛的?

Java虚拟机是在Java程序运行过程中为程序分配内存空间的。

说到内存空间,Java虚拟机把他所管理的内存分为了若干个不同的数据区域,他们各自又各自的工作。各自拥有创建与销毁的时间点,有的区域随着虚拟机进程的启动就存在了,有的区域根据用户使用线程的启动和结束而创建与销毁。以下是Java虚拟机 运行时的内存数据区域。如下图所示

20191210001482\_1.png

上图中方法区空间是所有线程共享的数据区。

程序计数器

程序计数器在虚拟机内存中是一块比较小的内存空间。他的作用是当前线程所执行编译后代码(字节码)行号的说明(计数器)。

Java虚拟机的多线程是通过线程轮流切换并分配处理器执行的时间来实现的,在确定的一个时刻处理器只能执行一条线程中的指令。当我们执行完这条指令后还需要恢复到原来的位置。所以每条线程都需要一个独立的程序计数器来记录各自的结果。各个线程之间的程序计数器互不影响,互相保持独立的存储,这样的内存区域也被称为”线程私有”的内存(相互保持独立互不影响)。

Java虚拟机栈

和程序计数器一样,Java虚拟机栈也是线程私有的,虚拟机栈描述的是Java方法执行情况下的内存模型。每个方法在执行的时候都会创建一个栈帧。它是用来存储方法的局部变量,方法出口等信息。每一个方法从调用到执行完成的过程都对应这一个栈帧在虚拟机栈中从入栈到出栈的过程。

经常有人把Java内存区分为堆内存与栈内存(虚拟机栈)两个部分,其实这只是我们平常最关心也是最重要的两个部分,实际上Java内存区域的分配是比较复杂的。

局部变量在栈帧中所需要的内存空间在程序的编译器就已经完成了分配。方法的运行期间是不会改变局部变量所占用的内存空间的。

虚拟机栈在方法程序运行时会出现两种异常,当线程请求的深度大于虚拟机允许的最大深度后将会抛出StackOverflowError异常(栈溢出)。另外一种异常就是当无法申请到足够内存时会抛出OutOfMermoryError异常(内存泄漏)。

本地方法栈

Java堆

Java堆空间是被Java虚拟机管理的最多的一块内存空间,Java堆空间是所有线程共享的,什么是线程共享?就是一个线程对数据访问修改之后其他线程依然可以对其进行修改。堆空间存在的目的就是存放实例对象。实例对象就是Java类new出来的一个 对象。Java所有的实例对象都会在这里分配各自的内存空间。但是也不是绝对的。

Java堆空间也是Java垃圾回收主要管理的一片区域。现在一般的垃圾回收算法都是采用分代收集算法。堆空间可以被分为新生代和老年代。

方法区

方法区与Java堆空间相同,都是线程共享的区域。它主要存储被加载过类的信息,常量,静态变量,还有编译后的代码等。很多同学也把方法区称为“永久代”。为什么称之为永久代。因为这这个区域垃圾收集行为是比较少的。但是并不意味这进入这个区域的数据就是永久存在了。这只是一个相对的概念。在方法区中主要回收的目标就是常量池。常量池也是方法区的一部分。

运行时常量池

运行时常量池就是在上文提到的,它属于方法区的一部分。当我们的虚拟机运行一个被编译后的Java文件时。文件中包含这个类版本,方法,接口,字段等信息,还有一个重要的就是常量池,常量池中存放着程序编译产生的字面量和符号的引用。这个常量池就被存放在了方法区中的运行时常量池中。

举一个最实用的例子。常量池在String类中的应用。当我们定义一个String字符串时,我们都知道String具有不可变性。他首先回去常量池中寻找有没有与我们定义的字符串相同的字面量,如果有的话直接将这个字面量的引用返回。如果没有自动创建一个新的字面量然后将其返回。运行时常量池属于方法区一部分那么他肯定遵循方法区的内存分配,当无法申请到足够的内存时依然会抛出OutOfMemoryError异常。

点赞(0)
版权归原创作者所有,任何形式转载请联系作者; Java 技术驿站 >> Java虚拟机的理解与内存模型之间的区别

相关推荐