摘要:虚拟机运行时数据区虚拟机在执行程序的过程中会把它管理的内存划分为若干个不同的数据区域。此内存区域是唯一一个在虚拟机规范中没有规定任何情况的区域。
java虚拟机运行时数据区
java虚拟机在执行java程序的过程中会把它管理的内存划分为若干个不同的数据区域。根据《Java 虚拟机规范(Java SE 7版)》规定,Java虚拟机所管理的内存将会包括一下几个运行时数据区域。
程序计数器程序计数器是一块较小的内存空间,它可以看作是当前线程执行的字节码的行号指示器。
在虚拟机的概念模型,字节码解释器工作时,就是通过改变这个计数器的值来选取下一条需要执行的字节码指令。
每条线程都有一个独立的程序计数器。为了线程切换后能恢复到正确的执行位置。java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式实现的,一个处理器(对于多核处理器来说就是一个内核)都只会执行一条线程中的指令。
如果线程执行的是java方法,这个计数器记录的是正在执行的虚拟机字节码指令地址。如果是native方法,计数器为空。此内存区域是唯一一个在java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。
java方法能按照顺序去执行去调用,就是因为有了这个程序计数器。
java虚拟机栈java虚拟机栈也是线程私有的,虚拟机栈描述的是Java方法执行的内存模型。
每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。一个方法对应一个栈帧。
局部变量表存放了各种基本类型、对象引用和returnAddress类型(指向了一条字节码指令地址)。其中64位长度long 和 double占两个局部变量空间,其他只占一个。
规定的异常情况有两种:
1.线程请求的栈的深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;
2.如果虚拟机可以动态扩展,如果扩展时无法申请到足够的内存,就抛出OutOfMemoryError异常。
本地方法栈(Native Method Stack)和虚拟机栈所发挥的作用非常相似,它们之间的区别在于:
虚拟机栈是为虚拟机执行java方法(也就是字节码服务)
而本地方法栈则为虚拟机使用到的Native方法服务
本地方法栈也是线程私有的,也会抛出StackOverflowError和OutOfMemoryError
java堆Java堆(Java Heap)是Java虚拟机所管理的内存中最大的一块。Java堆是所有线程共享的一块内存区域,在虚拟机启动时创建。
java堆的唯一目的就是存放对象实例对象。几乎所有的对象实例都在这里分配。这一点在java虚拟机规范中描述:所有的对象实例以及数组都要在堆上分配,但随着JIT编译器的发展与逃逸分析技术的成熟,所有的对象都分配在堆上也变的不是那样“绝对”了。
java堆是垃圾收集器管理的主要区域,因此很多地方也称为“GC堆”,从内存回收角度看,由于现在收集器基本都采用分代收集算法,java堆中还可以细分:新生代、老年代。新生代再细分可分为Eden空间、From Survivor空间、To Survivor空间。
当前主流的虚拟机的堆空间都是按照可扩展来实现的,通过(-Xmx和-Xms控制)。堆无法扩展时,抛出OutOfMemoryError异常
方法区方法区(Method Area)与java堆一样,是各个线程共享的内存区域,它用来存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但它有个别名叫做Non-Heap(非堆)
在HotSpot虚拟机上,很多人将方法区称为“永久代”,本质上两者并不等价。方法区是一个抽象的说法,永久代是方法区的具体实现。GC的设计团队选择把GC分代收集扩展至方法区。这样HotSpot的垃圾收集器可以像管理Java堆一样管理这部分内存。
在JDK1.7的HotSpot中,已经将原本放在永久代的字符串常量池移出,jdk1.7,逐步开始抛弃方法区,将字符串常量池移至堆区.这里jdk文档并没有说运行时常量池是否也跟着移到堆区,也就是说运行时常量依然在方法区,永久代仍存在于JDK1.7中
jdk1.8,JVM移除了永久区,取而代之的是元空间(Metaspace) ,也就是将本地内存用来存储.容量取决于是32位或是64位操作系统的可用虚拟内存大小).这时候字符串常量池还在堆, 运行时常量池还在方法区, 只不过方法区的实现从永久代变成了元空间.
当方法区无法满足内存分配需求时,抛出OutOfMemoryError异常
运行时常量池运行时常量池(Runtime Constant Pool)是方法区的一部分,Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息就是常量池(Constant Pool Table),用于存放编译期生成的各种字面量和符号引用。这部分内容将在类加载后进入方法区的运行时常量池存放。
相较于Class文件常量池,运行时常量池更具动态性,在运行期间也可以将新的变量放入常量池中,而不是一定要在编译时确定的常量才能放入。最主要的运用便是String类的intern()方法
jdk1.6及以下版本:它位于永久代-方法区中
jdk1.7,逐步开始抛弃方法区,将字符串常量池移至堆区.这里jdk文档并没有说运行时常量池是否也跟着移到堆区,也就是说运行时常量依然在方法区,永久代仍存在于JDK1.7中
jdk1.8,JVM移除了永久区,这时候字符串常量池还在堆, 运行时常量池还在方法区, 只不过方法区的实现从永久代变成了元空间.
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/75853.html
摘要:虚拟机运行时数据区分为以下几个部分。程序计数器也是在虚拟机规范中唯一没有规定任何异常情况的区域。在方法运行期间不会改变局部变量表的大小。长度在位和位的虚拟机中,分别为官方称它为。 Java虚拟机运行时数据区 详解 2.1 概述 本文参考的是周志明的 《深入理解Java虚拟机》第二章 ,为了整理思路,简单记录一下,方便后期查阅。 2.2 运行时数据区域 Java虚拟机在Java程序运行时...
摘要:虚拟机在执行程序的过程中会把它所管理的内存划分为若干个不同的数据区域。栈帧栈帧是用于支持虚拟机进行方法调用和方法执行的数据结构,它是虚拟机运行时数据区中的虚拟机栈的栈元素。栈帧的概念结构如下运行时数据区脑图高 这里我们先说句题外话,相信大家在面试中经常被问到介绍Java内存模型,我在面试别人时也会经常问这个问题。但是,往往都会令我比较尴尬,我还话音未落,面试者就会背诵一段(Java虚拟...
摘要:小结程序计数器和虚拟机栈是线程私有的,而堆和方法区是线程共享的除了虚拟机运行时内存,在中使用类可以直接操作本机内存。 Java的内存区域 Java虚拟机在执行Java程序中会把它所管理的内存划分为若干个数据区域,这些区域有各自的用途,以及生命周期,有些依赖虚拟机进程启动而存在,有些依赖用户线程的启动和结束而建立和销毁 运行时内存 showImg(/img/bVqUpc); 程序计数器(...
摘要:方法区在实际内存空间站可以是不连续的。这一规定,可以说是给了虚拟机厂商很大的自由。但是值得注意的是,堆其实还未每一个线程单独分配了一块空间,这部分空间在分配时是线程独享的,在使用时是线程共享的。 在我的博客中,之前有很多文章介绍过JVM内存结构,相信很多看多我文章的朋友对这部分知识都有一定的了解了。 那么,请大家尝试着回答一下以下问题: 1、JVM管理的内存结构是怎样的? 2、不同的...
摘要:抽时间重新读了一遍深入理解一书。验证确保文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。可见性可见性是指当一个线程修改了共享变量的值,其他线程能够立即得知这个修改。 抽时间重新读了一遍《深入理解JVM》一书。以下为摘录内容。 1 java内存区域 showImg(https://segmentfault.com/img/bVboDgk?w=617&h=365...
阅读 3490·2019-08-30 15:53
阅读 3404·2019-08-29 16:54
阅读 2189·2019-08-29 16:41
阅读 2396·2019-08-23 16:10
阅读 3376·2019-08-23 15:04
阅读 1341·2019-08-23 13:58
阅读 346·2019-08-23 11:40
阅读 2451·2019-08-23 10:26