Java虚拟机运行时数据区域汇总

 更新时间:2019年08月14日 09:18:05   作者:天天不是小可爱  
这篇文章主要给大家介绍了关于Java虚拟机运行时数据区域的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Java具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧

程序计数器(Program Counter)

程序计数器作为一个概念模型,这个是用来指示下一条需要执行的字节码指令在哪。

Java的多线程实际上是通过线程轮转做到的,如果是一个单核的机器(或单cpu),严格意义上在一个时间块中只会有一个线程在执行。为了线程切换以后能恢复到正确的执行位置,每个线程都需要有一个单独的计数器,每个计数器之间要是独立的互不干扰。

如果线程执行的是Java方法,那么PC指向的是正在执行的虚拟机字节码指令的区域,如果执行的是native方法,那么它是undefined。

Java虚拟机栈

Java virtue machine也是线程私有的,它拥有一个和线程相同的生命周期

虚拟机栈描述的是Java方法执行的内存模型;stack frame(栈帧)是一个经常谈及的概念,它用来储存内部变量表,操作数栈,动态链接,方法出口等等。

每一个方法从调用到执行完毕,也就对应着一个栈帧在虚拟机栈中的入栈和出栈

我们以前画图来说明内存区的时候,总是去关注Heap(堆内存)和stack(栈内存)这两部分,这是与对象内存分配最相关的两块内存区。通常所说的stack就是虚拟机栈,或者更具体的说是虚拟机栈中的局部变量表。

局部变量表存放了编译器可知的各种基本数据类型(boolean byte double char int short long float)对象引用(reference类型,并不是对象本身,可能是地址的引用指针,也可能是一个代代表对象的句柄)return address类型(指向一条字节码指令的地址)

局部变量表的意义就在于,可以把表所需的内存在编译器就进行分配,每次程序去调用一个方法的时候,方法需要在frame中分配多少的局部内存空间是确定的。

两种异常情况

如果线程请求的栈的深度大于虚拟机所允许的,就是StackOverFlowError,如果是支持动态拓展的虚拟机(大部分的现代虚拟机都支持)依然无法申请到足够的内存,就会报出OutOfMemoryError异常。

本地方法栈

本地方法栈是和Java虚拟机栈对应的一个概念,它们的作用也是相近的,唯一的不同是,本地方法栈执行的是native方法,而Java虚拟机栈执行的是Java方法(也就是字节码)服务

在Sun的HotSpot虚拟机里面,本地方法栈和虚拟机栈是一个。

Java堆

堆是被所有的线程所共享的一块区域,这块内存区域存在的唯一目的就是存放对象实例,在虚拟机启动的时候就会被创建,几乎所有的对象实例都会在这里被分配内存

所有的对象实例和数组都要在堆上分配 --《Java虚拟机规范》

随着JIT编译器的发展和逃逸技术的成熟,这句话也变得不是那么的绝对了。

GC(garbage collection)也发生在这个区域,所以有时候也被称为GC堆

方法区

方法区和Java堆相似,是线程共享的一段内存区域,它用于储存已经被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码。

听起来好像和Java堆很像,Java虚拟机标准里面也把它视为堆的一个逻辑部分,但是它被称作Non-Heap,目的是和Java堆区分开来。

Permanent Generation?那么,这个方法区就是永久代吗,并不是。只是在HotSpot虚拟机的设计中,用永久代来实现了方法区。(在JDK1.7中,已经把原本放在永久代的字符串常量池移出了)

运行时常量池(Runtime Constant Pool)

这也是方法区的一个较重要的部分,.class文件除了有类的版本,字段,方法,接口等描述信息外,还有一部分是常量池,用于在存放编译期生成的各种字面量(Literal)和符号引用(Symbolic References),这部分的内容在类加载以后进入运行时常量池中存放。

字面量比较好理解,是Java语言层面的常量,例如文本字符串,声明为final的变量

符号引用这个我第一时间没看懂什么意思,其实是编译原理的一个概念,包括以下的三种常量:

  • 类和接口的全限定名
  • 字段名称和描述符
  • 方法名称和描述符

动态性,这是运行时常量池的一个重要的特性,在运行期间也可以将新的常量放进常量区(包括基本包装类和String,也可以调用intern()将String强制放进常量池)

为什么需要运行时常量池呢?

  • 更少的内存。直接赋值的时候会利用常量池里面的对象,而不是去new了一个
  • 更快的速度 。‘=='比equals()更快
Integer a = 23;//在编译的时候会变成Integer i1=Integer.valueOf(40);使用的是线程池里面的对象

Integer b = new Integer(23);//创建了新的对象

ps.我感觉这个的设计思路和数据库连接池是差不多的,可以对照着去理解。

参考资料

《深入理解Java虚拟机》

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对脚本之家的支持。

相关文章

  • Android Studio中创建java工程的完整步骤

    Android Studio中创建java工程的完整步骤

    Android Studio创建java工程是非常麻烦的,因为Android Studio没有提供直接创建java工程的方法,下面这篇文章主要给大家介绍了关于Android Studio中创建java工程的完整步骤,需要的朋友可以参考下
    2024-01-01
  • java &与&&的区别及实例

    java &与&&的区别及实例

    这篇文章主要介绍了java &与&&的区别的相关资料,并附简单实例,帮助大家学习理解这部分知识,需要的朋友可以参考下
    2016-10-10
  • springboot jackson配置教程

    springboot jackson配置教程

    这篇文章主要介绍了springboot jackson配置教程,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • MyBatis连接池的深入和动态SQL详解

    MyBatis连接池的深入和动态SQL详解

    这篇文章主要介绍了MyBatis连接池的深入和动态SQL详解,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-02-02
  • java基于Des对称加密算法实现的加密与解密功能详解

    java基于Des对称加密算法实现的加密与解密功能详解

    这篇文章主要介绍了java基于Des对称加密算法实现的加密与解密功能,结合实例形式详细分析了Des加密算法的功能、原理、使用方法与相关注意事项,需要的朋友可以参考下
    2017-01-01
  • MyBatis中insert操作返回主键的实现方法

    MyBatis中insert操作返回主键的实现方法

    在使用MyBatis做持久层时,insert语句默认是不返回记录的主键值,而是返回插入的记录条数。这篇文章主要介绍了MyBatis中insert操作返回主键的方法,需要的朋友可以参考下
    2016-09-09
  • Java项目在Idea中开发遇到所有代码爆红的问题与解决办法

    Java项目在Idea中开发遇到所有代码爆红的问题与解决办法

    今天打开项目时发现idea竟然爆红,通过查找相关资料用于解决,下面这篇文章主要给大家介绍了关于Java项目在Idea中开发遇到所有代码爆红的问题与解决办法的相关资料,需要的朋友可以参考下
    2023-06-06
  • Java多线程ThreadPoolExecutor详解

    Java多线程ThreadPoolExecutor详解

    这篇文章主要介绍了Java多线程ThreadPoolExecutor详解,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-08-08
  • Java递归 遍历目录的小例子

    Java递归 遍历目录的小例子

    Java递归 遍历目录的小例子,需要的朋友可以参考一下
    2013-03-03
  • SpringCloud声明式Feign客户端调用工具使用

    SpringCloud声明式Feign客户端调用工具使用

    这篇文章主要为大家介绍了SpringCloud声明式Feign客户端调用工具使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08

最新评论