资讯专栏INFORMATION COLUMN

JVM 探究(一):JVM内存模型概念模型

cnTomato / 2231人阅读

摘要:作为一个程序员,不了解内存模型就不能写出能够充分利用内存的代码。程序计数器是在电脑处理器中的一个寄存器,用来指示电脑下一步要运行的指令序列。在虚拟机中,本地方法栈和虚拟机栈是共用同一块内存的,不做具体区分。

作为一个 Java 程序员,不了解 Java 内存模型就不能写出能够充分利用内存的代码。本文通过对 Java 内存模型的介绍,让读者能够了解 Java 的内存的分配情况,适合 Java 初学者或者对 JMM 不熟悉的同学。后面的博客会针对每个部分做更加深入的解释。

Java 内存模型

首先通过下图对于 Java 内存模型有一个整体的认识,然后针对不同的区域的作用和存储的内容做进一步的解释。

PC(程序计数器)

这里的 PC 不是 Personal Computer,而是 Program Counter Register,从名字就可以看出来,这是一个寄存器,用来存储需要执行的指令地址。

程序计数器(Program Counter (PC))是在电脑处理器中的一个寄存器,用来指示电脑下一步要运行的指令序列。--WikiPedia

PC 和其他 JVM 内存区域最大的区别是:

“此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。
摘录来自: 周志明. “深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)”。 iBooks.

像上面的图片一样,PC 是每个线程私有的,对于 Java 方法而言,PC 中存储的是正在执行的虚拟机字节码的内存地址;对于 Native 方法来说,PC 中的值为空(Undefined)。

Java 虚拟机栈和本地方法栈 虚拟机栈

无论是在大学的 Java 编程课堂上,还是我们在学习过程编码过程,经常会出现 StackOverFlow,甚至目前最大的技术问答社区的名字也是 StackOverFlow。Java 语言中会产生栈溢出的就是这块内存区域,当你的程序中设置了超过 JVM 规定的递归深度的时候就会触发这个异常。类似 JMM 的其他内存区域,如果虚拟机栈在动态扩展的时候无法申请到足够的内存也会报OOM异常。

Java 语言中每一个方法的执行都对应着一个栈帧(Stack Frame)的创建,栈帧中存储的是局部变量、方法出口等信息,因此对于一个方法的执行而言,所能够使用到的内存是在编译期间就能够完全确定的,在运行期间不会发生变化。在栈帧中,局部变量空间成为 Slot,除了 double 和 long 占有 2 个 slot 外,其他基本数据类型和对象引用都占用 1 个 slot 空间

本地方法栈

本地方法栈和虚拟机栈最大的区别就是虚拟机栈是为执行 Java 字节码服务的,而本地方法栈是为了虚拟机使用到的 Native 方法服务的。除此之外,Java 虚拟机规范并没有针对本地方法栈的实现做具体规定。在 HotSpot 虚拟机中,本地方法栈和虚拟机栈是共用同一块内存的,不做具体区分。同样,本地方法栈也会产生 OOM 异常和 StackOverFlow 异常。

Java 堆
“The heap is the runtime data area from which memory for all class instances and arrays is allocated。” --Java虚拟机规范

Java 虚拟机规范规定所有的实例对象和数组都应该分配到 Java 堆中。
说的通俗一点就是所有 new 出来的对象和数组都会放到该区域,由于现在的收集器都采用分代收集算法,所以在 Java 堆中又分了新生代和老年代,新生代有做了详细的区分。该区域的大小可以通过 JVM 参数 -Xmx-Xms 来设置。

直接内存

在 JDK1.4 中引入了 NIO,可以通过 Native 方法直接在堆外分配内存,然后通过在堆中存储的引用来对这块内存区域做操作。注意 这块区域并不会在 -Xmx-Xms 设置的大小之内,因此在设置 JVM 参数的时候要注意考虑这块内存区域,避免设置的内存区域总额大于物理内存

方法区

Method Area 又叫 NonHeap,也是线程共有的内存区域,用来存:

类信息

常量

静态变量

字符串常量池

在 JDK1.7 中已经将字符串常量池移出永久代,在 Java8 中更是之内取消了永久代,而是使用了元空间(MetaSpace)来存储这些信息,从而永久代的大小不需要再制定,只要不超出物理内存的限制就不会产生 OOM 异常

运行时常量池

运行时常量池主要用来存储累的版本、字段、方法、接口等描述信息。常量池(Constant Pool Table)用来存储各种字面量和符号引用。String 的 intern() 方法就是在运行期间将对象放到常量池中的。此部分也会出现 OOM 异常。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/69540.html

相关文章

  • Java性能优化之JVM内存模型

    摘要:内存模型首先介绍下程序具体执行的过程源代码文件后缀会被编译器编译为字节码文件后缀由中的类加载器加载各个类的字节码文件,加载完毕之后,交由执行引擎执行在整个程序执行过程中,会用一段空间来存储程序执行期间需要用到的数据和相关信息,这段空间一般被 [TOC] JVM内存模型 首先介绍下Java程序具体执行的过程: Java源代码文件(.java后缀)会被Java编译器编译为字节码文件(....

    SQC 评论0 收藏0
  • jvm原理

    摘要:在之前,它是一个备受争议的关键字,因为在程序中使用它往往收集器理解和原理分析简称,是后提供的面向大内存区数到数多核系统的收集器,能够实现软停顿目标收集并且具有高吞吐量具有更可预测的停顿时间。 35 个 Java 代码性能优化总结 优化代码可以减小代码的体积,提高代码运行的效率。 从 JVM 内存模型谈线程安全 小白哥带你打通任督二脉 Java使用读写锁替代同步锁 应用情景 前一阵有个做...

    lufficc 评论0 收藏0
  • 后台开发常问面试题集锦(问题搬运工,附链接)

    摘要:基础问题的的性能及原理之区别详解备忘笔记深入理解流水线抽象关键字修饰符知识点总结必看篇中的关键字解析回调机制解读抽象类与三大特征时间和时间戳的相互转换为什么要使用内部类对象锁和类锁的区别,,优缺点及比较提高篇八详解内部类单例模式和 Java基础问题 String的+的性能及原理 java之yield(),sleep(),wait()区别详解-备忘笔记 深入理解Java Stream流水...

    spacewander 评论0 收藏0
  • 后台开发常问面试题集锦(问题搬运工,附链接)

    摘要:基础问题的的性能及原理之区别详解备忘笔记深入理解流水线抽象关键字修饰符知识点总结必看篇中的关键字解析回调机制解读抽象类与三大特征时间和时间戳的相互转换为什么要使用内部类对象锁和类锁的区别,,优缺点及比较提高篇八详解内部类单例模式和 Java基础问题 String的+的性能及原理 java之yield(),sleep(),wait()区别详解-备忘笔记 深入理解Java Stream流水...

    xfee 评论0 收藏0
  • 后台开发常问面试题集锦(问题搬运工,附链接)

    摘要:基础问题的的性能及原理之区别详解备忘笔记深入理解流水线抽象关键字修饰符知识点总结必看篇中的关键字解析回调机制解读抽象类与三大特征时间和时间戳的相互转换为什么要使用内部类对象锁和类锁的区别,,优缺点及比较提高篇八详解内部类单例模式和 Java基础问题 String的+的性能及原理 java之yield(),sleep(),wait()区别详解-备忘笔记 深入理解Java Stream流水...

    Brenner 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<