JVM内存区域之线程私有区域

日期:2020-12-01 12:11:33 来源:互联网 编辑:小优 阅读人数:216

概述:

对于从事C、C++的程序员来说,在内存领域,他们既是拥有最高权力的“皇帝”又是从事最基础工作的劳动人民—既拥有每个对象的“所有权”

又担负着每一个对象从开始到终结的维护职责。

对于java程序员来说,在虚拟机自动内存机制的帮助下,不再需要为没一个new操作去配对的free/delete(C、C++语言对对象的删除和内存释放操作)

不容易出现内存泄漏和内存溢出问题,看起来由虚拟机内存一切看起来很美好。不过,也正是java把控制内存的权力交给了java虚拟机,一旦出现内存泄漏

和内存溢出方面的问题,如果不了解虚拟机是怎么使用内存的,那排查错误、修正问题将会成为一项异常艰难的工作。

运行时数据区:

java虚拟机在执行java程序的过程中会把它所的内存划分为若干个不同的数据区域。这些区域有各自的用途,以及创建和销毁的时间,有些区域会随着

虚拟机进程的启动而一直存在,有些区域则是依赖用户线程的启动和结束而建立和销毁。如下图所示:

JVM内存区域之线程私有区域(图1)

我们知道JVM也属于一种特殊的操作,那这些数据区域跟我们最常用的windows哪些部分相对应呢。我们可以把windows的CPU+缓存+主内存和JVM的执行引擎+

操作数栈+(栈、堆)对应起来,这样更加利于我们去理解JVM。

虚拟机栈:

从上图可见,java虚拟机栈是线程私有的,它的生命周期和线程相同。虚拟机栈描述的是java方法执行的线程内存模型:每个方法被执行的时候,java虚拟机都会

出栈的过程。我们来通过一段非常简短的代码来演示虚拟机栈的作用:

JVM内存区域之线程私有区域(图2)

当我们运行main方法,虚拟机会开启一个线程,同时为当前线程划分一块内存区域作为当前线程的虚拟机栈。同时在执行每个方法的时候都会打包成一个栈帧。

比如 main 开始运行,打包一个栈帧送入到虚拟机栈。C 方法运行完了,C 方法出栈,接着 B 方法运行完了,B 方法出栈、接着 A 方法运行完了,A 方法出栈。

最后 main 方法运行完了,main 方法这个栈帧就出栈了。这个就是 Java 方法运行对虚拟机栈的一个影响。虚拟机栈就是用来存储线程运行方法中的数据的。而

每一个方法对应一个栈帧。入栈过程如下图所示:

JVM内存区域之线程私有区域(图3)

上图描述了整个main方法调用的入栈和出栈的过程,需要注意的是栈帧出栈之后就没了,栈帧没得GC的说法。

栈帧详解:

局部变量表:顾名思义就是局部变量的表,用于存放我们的局部变量的(方法中的变量)首先它是一个 32 位的长度,主要存放我们的 Java 的八大基础数据

操作数栈:存放 java 方法执行的操作数的,它就是一个栈,先进后出的栈结构,操作数栈,就是用来操作的,操作的的元素可以是任意的 java 数据类型,所

以我们知道一个方法刚刚开始的时候,这个方法的操作数栈就是空的。操作数栈本质上是 JVM 执行引擎的一个工作区,也就是方法在执行,才会对操作数栈进行操作,如果代码不不执行,操作数栈其实就是空的。

动态连接:Java 语言特性多态(后续章节细讲,需要结合 class 与执行引擎一起来讲)

我们来通过分析一个简单的方法来理解栈帧中各个区域是如何运作的,代码如下:

JVM内存区域之线程私有区域(图4)

当该程序运行的时候,JVM会为其分配虚拟机栈,并生成对应的栈帧,如下图所示:

JVM内存区域之线程私有区域(图5)

我们通过反汇编命令查看work方法的字节码如下:

JVM内存区域之线程私有区域(图6)

我们看到work方法一共由10条字节码组成,我们来逐步分析。

JVM内存区域之线程私有区域(图7)

所以第1个字节码是将一个值为2的数字加载到操作数栈。再来看 istore_0的含义,如图

JVM内存区域之线程私有区域(图8)

所以第2个字节码的含义就是将第一步中放入到操作数栈的数字放到局部变量表中,位置为0。所以前面两个字节码对应的java代码就是int a = 2;那么显而易见3和4两个字节码对应的

就是int b = 3;到这里,大家心里肯定会有疑问,为什么不直接将值放到局部变量表呢?我们接着分析,你就明白了。

继续来看第5和第6两个字节码:iload_0和iload_1,它们的含义是将局部变量表中位置0和1的两个数加载到操作数栈中,接着我们来看关键的第7个字节码:imul,它代表的意思

是相乘,就是将操作数栈中的数字进行乘法运算,我们知道相乘是需要运算的,所以此时要交给执行引擎运算,运算完成之后再将运算的结果返回到操作数栈。所以操作数栈的作用

就是为jvm高速的计算提供缓冲区。

接着来看第8个字节码:istore_2,它的含义就是将计算的结果放入局部变量表,到这里int c = a*b;就执行完了。再来看第9和第10个字节码,它们的含义是将局部变量表的值再

压入操作数栈,最后返回。至此,整个方法执行结束,以上就是栈帧中各个区域在方法执行中的运作流程。

虚拟机栈大小的设置:

虚拟机栈的大小缺省为 1M,可用参数 –Xss 调整大小,例如-Xss256k。

JVM内存区域之线程私有区域(图9)

虚拟机栈相关的程序异常:

StackOverflowError异常:如果线程请求的栈深入大于虚拟机所允许的深度,将抛出StackOverflowError异常,通常是由无线递归导致的,如下面的代码

JVM内存区域之线程私有区域(图10)

OutOfMemoryError:如果java虚拟机的容量可以动态扩展,当栈扩展时无法申请到足够的内存会抛出OutOfMemoryError异常。这种情况基本很少出现,也很难模拟,这里就不演示了。

程序计数器:

JVM内存区域之线程私有区域(图11)

如上图所示,虽然这些序号是由顺序的,但是并不一定是依次递增,如果某给字节码占用的空间很大,那么它的序号相较于前一个序号就差距更大。

在java虚拟机的概念模型里,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,它是程序控制流的执行器,分支。

循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器完成。

它还有另外一个作用,我们知道在java中可以开启成百上千个线程,但是我们一般的电脑CPU也就8个左右。java虚拟机的多线程是通过线程轮流切换。

分配处理器执行时间方式来实现的,那么切换后虚拟机是怎么知道以前运行的位置,继续运行的呢?这个时候,程序计数器就起到了决定性的作用,因为

程序计数器是线程独有的,所以不会相互影响,当切回到当前线程,根据程序计数器记录的序号,继续执行对应的字节码即可。

则应为空(Undefined)但是这里会产生一个疑问,如果刚好在执行Native方法的时候线程切换了,那切回来之后该怎么找到对应的位置呢?这里,我猜测

JVM可能规定了 在执行Native本地方法的时候,禁止切换当前线程(如不正确,请指正)xianc

本地方法栈:

本地方法栈与虚拟机栈的作用非常相似,其区别只是虚拟机栈为java方法服务,而本地方法栈专门为Native本地方法服务。需要注意的是,HotSpot直接把

本地方法栈和虚拟机栈合并了。

总结:

本篇文章介绍了JVM的内存区域之线程私有区域,主要介绍了虚拟机栈的各个组成部分以及java方法是怎么通过虚拟机栈来实现执行的,接着介绍了程序计数器的作用

最后简述了本地方法栈。下一章,我们将要分析JVM内存区域的线程共享数据区,主要包括堆、方法区、运行时常量池以及直接内存等内容。

本文相关词条概念解析:

线程

线程,计算机科学术语,有时也被称为轻量级进程(Light Weight Process,LWP),它是运行中的程序的调度单位。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。线程被包含在进程之中,是进程的一个实体,是CPU调度和分派的基本单位它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。

延伸 · 推荐

虚拟机栈为虚拟机执行Java方法,栈是JVM运行时的单位

一、内存与线程1、内存结构内存是计算机的重要部件之一,它是外存与CPU进行沟通的桥梁,计算机中所有程序的运行都在内存中进行,内存性能的强弱影响计算机整体发挥的水平。JVM的内存结构规定Java程序在执...

程序员大补文章,一个JVM实例只存在一个堆内存

堆得核心概述1. 一个JVM实例只存在一个堆内存,堆也是java内存的核心区域2.Java堆区在jvm启动的时候被创建,其空间大小也就确定了。是jvm的最大一块内存空间。堆内存的大小可以调节3.《ja...

网友评论
相关文章
既然新城规划四面八方开花,到底谁才是惠州最牛逼的那个区域

既然新城规划四面八方开花,到底谁才是惠州最牛逼的那个区域

既然新城规划四面八方开花,到底谁才是惠州最牛逼的那个区域[详情]

程序猿面试技能之redis(下)

程序猿面试技能之redis(下)

程序猿面试技能之redis(下)[详情]

2020年开篇: 堆、栈、方法区、类加载器——JVM 内存模型分析

2020年开篇: 堆、栈、方法区、类加载器——JVM 内存模型分析

2020年开篇: 堆、栈、方法区、类加载器——JVM 内存模型分析[详情]

网站地图    Copyright     2016-2018  资讯网   All rights reserved.