JVM运行时数据管理区

Posted 要千

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JVM运行时数据管理区相关的知识,希望对你有一定的参考价值。

JVM 在执行java程序的过程中会把它所管理的内存划分若干个不同的数据区域,这些区域用途不同,创建及销毁时间也不同,有些区域随着虚拟机的进程启动而存在,有些区域则随着用户进程的启动结束而创建和销毁根据java se 7规定,jvm管理的内存包括一下几个运行时数据区域如图:


介绍:

程序计数器:

       是一块较小的内存空间,它可以看做是当前线程所执行字节码的行号指示器。在jvm概念模型中,字节码解释器工作时就是通过改变这个计数器的值来获取下一条需要执行的字节码指令,分支,循环,跳转,异常等都需要依赖这个计数器完成,由于虚拟机的多线程是通过线程切换并分配处理器执行时间的方式实现的,在任意时刻,一个处理器都只会处理一个线程中的指令,因此为了线程切换后,能够正确的找到上次线程执行位置,每个线程需要有一个独立的线程计数器,各个线程计数器之间互不影响,独立存储,我们称之为线程独有的内存,如果线程正在执行一个java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址,如果是native方法,计数器为空,此块区域是jvm规范中唯一没有规定outOfMememoryError的区域

虚拟机栈:

        跟程序计数器一样,也是线程私有,声明周期跟线程相同,虚拟机栈描述的是java方法执行的内存模型:每个方法在执行的同时,都会创建一个栈帧,用于存储局部变量表,操作数栈,动态链接,方法出口等信息,一个方法从调用到执行结束对应着一个栈帧在虚拟机栈中入栈到出栈的过程,有人常说的栈内存和堆内存中栈内存,准确的说就是指虚拟机栈,或者说虚拟机栈中的局部变量表部分,如下图:



局部变量表存储了编译期间可知的基本数据类型boolean,byte,char,short ,int,long,float,double,对象引用,returnAddress类型(指向一条字节码指令地址),其中long,double会占2个局部变量空间(slot),其余的数据类型占1个,局部变量表的内存空间在编译期间已经分配好,当进入一个方法,这个方法需要的栈帧中分配多大的内存空间是完全确定的,方法运行期间不会改变局部变量表的大小,在jvm规范中,对这部分区域规定了两种异常状况,1如果线程请求的栈深度大于虚拟机所允许的深度,抛出StackOverflowError异常,不过当前的虚拟机大部分是可以动态扩展的,如果扩展申请不到足够的内存将报OutOfMemoryError异常


本地方法栈:

        本地方法栈跟虚拟机栈的发挥作用非常相似,区别不过是一个执行java方法,一个执行native方法,因为jvm规范中并没有对本地方法栈中方法使用的语言,使用方法与数据结构有强制规定,因此不同的jvm实现不同,比如sun HotSpot虚拟机直接将本地方法栈和虚拟机栈合二为一


java堆:

    对于大多数应用来说,java堆是java虚拟机管理的内存中最大一部分,被所有线程共享,在虚拟机启动时创建,此区域唯一的目的就是存放对象实例,几乎所有对象实例都存储在堆中,所有的对象实例和属组都在堆上进行分配,但是随着JIT编译器的发展和逃逸分析技术成熟,栈上分配,标量替换优化技术将导致一些微妙的变化,堆区也是垃圾回收机制管理的主要区域,由于现代收集器基本采用分代收集算法,所以java堆可以细分为新生代和老生代,再细致的分法有Eden空间,from Survivor空间,To Survivor空间等。从内存分配角度上看,堆内存可能划分出多个线程私有的分配缓冲区(TLAB),不管如何分,存的都是对象实例,主要是为了更好的回收内存,或者更快的分配。堆可以处在物理上不连续的内存空间,只要逻辑上连续即可,当前的堆内存都是可扩展的(-Xms -Xmx),如果堆中没有足够的内存完成实例分配,将会抛OutOfMemoryError

       

方法区:

    跟堆区一样,是所有线程共享的内存区域,用于存储虚拟机加载的类信息,常量,静态变量,即时编译器编译后代码等数据,虚拟机规范把它描述为堆的一个逻辑部分, 但是它有个别名叫non-heap,应当把它跟堆区分开来。对于HotSpot虚拟机上开发人员来说,方法区称为永久代(Permanent Generation),本质上二者不等价,只是HotSpot开发团队把GC分代管理扩展至方法区,这样垃圾收集器可以像管理堆一样管理方法区。其他虚拟机没有永久代这个概念。使用永久代实现方法区,现在看来并不是个好主意,更容易导致OutOfMemoryError(永久代有-XX:MaxPermSize的上限,其他如JRockit,J9只要没有触碰到进程可用内存上线,就不会出现问题),而且极少数方法String.intern()会因为这个导致不同虚拟机下的不同表现,官方发布的信息,有放弃永久代,并用NativeMemory实现方法区的规划,在jdk1.7中已经将字符串常量池移除永久代了,这部分的实现规范并没有限制,可以选择不实现垃圾回收。



以上是关于JVM运行时数据管理区的主要内容,如果未能解决你的问题,请参考以下文章

JVM 专题六:运行时数据区概述

深入理解JVM虚拟机:Java运行时数据区域

在 AS3 中获取翻转时数据网格组件的索引

JVM

Zabbix原厂认证中文培训师达3位,上海宏时数据实力

学完了这篇JVM,面试官真拿我没办法了!