当前位置: 首页 > news >正文

Java虚拟机在执行程序时内存划分的区域都有哪些?

温馨提示:阅读本文需要5-6分钟(无代码)
来源:《深入理解Java虚拟机》


今天,我们来解决一个问题:

Java虚拟机在执行程序时内存划分的区域都有哪些?

人生一切难题,知识给你答案。


Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。

==程序计数器==

程序计数器是一块较小的内存空间,它可以看做是当前线程所执行的字节码的行号指示器。在虚拟机的概念里,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。

由于Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)都只会执行一条线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间计数器互补影响,独立存储,属于线程私有的数据区域。

如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是Native方法,这个计数器值则为空(Undefined)。此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。

==Java虚拟机栈==

与程序计数器一样,Java虚拟机栈也是线程私有的,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。

局部变量表存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference类型,它不等同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或其他与此对象相关的位置)和returnAddress类型(指向了一条字节码指令的地址)。

在Java虚拟机规范中,对这个区域规定了两种异常情况:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果虚拟机栈可以动态扩展,如果扩展时无法申请足够的内存,就会抛出OutOfMemoryError异常。

==本地方法栈==

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

==Java堆==

对于大多数应用来说,Java堆是Java虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。Java堆是垃圾收集器管理的主要区域,因此很多时候也被称为“GC堆”。

从内存回收的角度来看,由于现在收集器基本都采用分代手机算法,所以Java堆中还可以细分为:新生代和老年代;再细致一点的有Eden空间、From Survivor空间、To Survivor空间等。

从内存分配的角度来看,线程共享的Java堆中可能划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer,TLAB)。

==方法区==

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

根据Java虚拟机规范的规定,当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常。

==运行时常量池==

运行时常量池是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,用于存放编译器生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。

当常量池无法再申请到内存时会抛出OutOfMemoryError异常。


相关文章:

  • 常见MQTT服务器搭建与试用
  • glutBitmapCharacter及glBitmap在ATI显卡下无法正常显示的原因初探
  • 俄罗斯“光影魔术”展亮相上海科技馆
  • AsyncTasLoader不进行加载操作的原因及解决方法
  • 一文详解Python字符串条件判断方法
  • 前端 CSS 规范
  • SpringBoot 实战 (三) | 配置文件详解
  • 搜索分词---产生新词的公式
  • ORA-22813 ORA-06512
  • MySQL 服务启动y异常: 本地无法启动MySQL服务,报的错误:1067,进程意外终止---解决...
  • Swift—UITextField的基本用法
  • xkb 第3章 虚拟 Modifiers
  • javascript 隐性类型转换步骤
  • 悲伤的结局!救援人员发现西班牙坠井男孩遗体
  • Python3-进程
  • 【108天】Java——《Head First Java》笔记(第1-4章)
  • 2017-08-04 前端日报
  • classpath对获取配置文件的影响
  • cookie和session
  • CSS相对定位
  • Gradle 5.0 正式版发布
  • WePY 在小程序性能调优上做出的探究
  • 百度地图API标注+时间轴组件
  • 动态规划入门(以爬楼梯为例)
  • 看图轻松理解数据结构与算法系列(基于数组的栈)
  • 罗辑思维在全链路压测方面的实践和工作笔记
  • 每天一个设计模式之命令模式
  • 如何在 Tornado 中实现 Middleware
  • 试着探索高并发下的系统架构面貌
  • 小李飞刀:SQL题目刷起来!
  • # Python csv、xlsx、json、二进制(MP3) 文件读写基本使用
  • # 再次尝试 连接失败_无线WiFi无法连接到网络怎么办【解决方法】
  • (1综述)从零开始的嵌入式图像图像处理(PI+QT+OpenCV)实战演练
  • (zt)最盛行的警世狂言(爆笑)
  • (非本人原创)史记·柴静列传(r4笔记第65天)
  • (附源码)python房屋租赁管理系统 毕业设计 745613
  • (附源码)ssm智慧社区管理系统 毕业设计 101635
  • (附源码)计算机毕业设计SSM智慧停车系统
  • (区间dp) (经典例题) 石子合并
  • (十六)串口UART
  • (详细版)Vary: Scaling up the Vision Vocabulary for Large Vision-Language Models
  • (转)关于pipe()的详细解析
  • .NET CF命令行调试器MDbg入门(二) 设备模拟器
  • .NET Core使用NPOI导出复杂,美观的Excel详解
  • .Net IOC框架入门之一 Unity
  • .Net 中Partitioner static与dynamic的性能对比
  • .NET/C# 避免调试器不小心提前计算本应延迟计算的值
  • .NetCore部署微服务(二)
  • .NET的微型Web框架 Nancy
  • .NET开发不可不知、不可不用的辅助类(三)(报表导出---终结版)
  • .NET应用架构设计:原则、模式与实践 目录预览
  • .sys文件乱码_python vscode输出乱码
  • @Autowired 与@Resource的区别
  • @NoArgsConstructor和@AllArgsConstructor,@Builder
  • @RequestParam,@RequestBody和@PathVariable 区别