上面已经聊过JVM是什么东东,也谈过了JVM内存的垃圾回收机制。这一篇博客我们来聊聊JVM运行时数据区域。

JVM运行时数据区域由5块部分组成,分别是堆,方法区,栈,本地方法栈,以及程序计数器组成。

可以根据内存是否线程共享划分成线程独享内存区域/线程共享内存区域。

我们从简单的部分开始吧

1.程序计数器

特点:线程内存独享,占用内存小,生命周期与线程相同(随线程诞生而诞生,随线程消亡而消亡)

功能:当前线程所执行的字节码的行号指示器。在虚拟机的概念模型里字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复(cpu在不断轮询执行任务)等基础功能都需要依赖这个计数器来完成

异常:该区域没有定义异常

2.栈(方法执行的动态模型)

特点:先进后出,线程内存独享,生命周期与线程相同

单位:栈帧

功能:已先进后出执行方法体的方法,执行完成的栈帧出栈

举例:

public static void main(String[] args) {
a();//调用a方法
b();//调用b方法
}

执行顺序

1.main函数的栈帧入栈

2.a方法的栈帧入栈

3.a方法执行完成后,a栈帧出栈

4.b方法的栈帧入栈

5.b方法执行完成后,b栈帧出栈

6.main方法执行完成后,main栈帧出栈,程序结束

异常:StackOverFlow(栈溢出),OutOfMemory(可以扩展栈内存的情况下,内存溢出)

接下来我们来谈谈栈的基本单位栈帧吧

栈帧(每一个方法对应一个栈帧)

只有虚拟机栈顶的栈帧才是有效的,称为当前栈帧 (Current Stack Frame),这个栈帧所关联的方法称为当前方法(Current Method)

组成:局部变量表,操作数栈,动态链接,方法出口信息4部分组成

1.局部变量表:由基本数据类型和对象引用组成的

作用:用来存储方法中的局部变量

基本单位:slot

局部变量表的大小在编译器就可以确定其大小了,因此在程序执行期间局部变量表的大小是不会改变的。

如果存储的是基本数据类型那么直接存储值
如果存储的是对象引用那么存储对象的引用地址( reference)(堆中)

补充:比较reference的两种实现方式

直接引用  vs 使用句柄池

直接引用

reference直接指向对象,对象中指向对象类型数据

优点:速度快,节约指针开销。HotSpot采用的主要方式

使用句柄池:

java堆中会维护一个句柄池,句柄池分别指向对象实例(堆)的和对象类型数据(方法区)

优点:对象移动后只需改变句柄池的指向地址,而不需要改变引用的指向地址。稳定

2.操作数栈

操作数栈的深度在编译器就可以确定其大小了,因此在程序执行期间局部变量表的大小是不会改变的。

功能:实现程序功能

3.动态连接

补充下直接引用与符号引用

直接引用:当类已经加载到虚拟机时,通过地址直接调用该类
符号引用(常量池中):在编译的时候还不知道类是否被加载,先用符号代替该类,等实际运行时再用直接引用替换间接引用。

静态解析:符号引用一部分会在类加载阶段或第一次使用的时候转化为直接引用
动态连接: 将在每一次的运行期期间转化为直接引用

4.方法出口信息

当一个方法执行完毕之后,要返回之前调用它的地方,因此在栈帧中必须保存一个方法返回地址。

但是出现异常会不会返回地址

补充:

局部变量,在方法内部声明,当该方法运行完时,内存即被释放。
成员变量,只要该对象还在,哪怕某一个方法运行完了,还是存在。
从系统的角度来说,声明局部变量有利于内存空间的更高效利用(方法运行完即回收)。
成员变量可用于各个方法间进行数据共享。

补充:栈帧的部分操作数栈与上面栈帧的部分局部变量表重叠在一起,这样在进行方法调用返回时就可以共用一部分数据,而无须进行额外的参数复制传递了

{
int a=;
a+=10;
method(a);
}void method(int num)
{
System.out.print(a);
}

通过这个例子我们看到如果不重叠的话,每次都要重新计算a+=10的值才能执行下面的方法。

3.本地方法栈

大体上都类似于虚拟机栈
不同点:栈执行的java方法服务
本地方法栈执行的是Native方法(不一定是用java开发的)服务

4.堆

特点:存储对象,线程间内存共享,占用大量内存,垃圾回收关注的重点区域
关于的堆的分类可以参考上一篇的java垃圾回收机制

异常:OutOfMemoryError

每次都向堆中存放对象,方法结束后,销毁栈帧的局部变量表时同时销毁引用,该对象就成了可回收的垃圾。咋看起来没什么不对呀,可是仔细思考下还是存在两个问题
1.不断的来回增加删除对象,对于GC的工作量太大。
2.java使指针碰撞(堆中存入新对象的时候,指针根据对象大小移动到相应位置)来为对象分配内存。如果在多线程的环境下,就会出现两个对象同时移动当前前指针的情况,造成线程不安全的情况。

这里就要引入TLAB的概念了

TLAB的全称是Thread Local Allocation Buffer,这是一个线程专用的内存分配区域。每个线程都会从Eden分配一块空间,当线程销毁时,我们自然可以回收掉TLAB的内存。

使用TLAB指令 -XX:UseTLAB

优点:线程安全,减少垃圾回收的压力。

缺点:TLAB空间大小是固定的,面对大对象的时候不够灵活

5.方法区

特点:存储类,线程间内存共享

存放已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据

异常:OutOfMemoryError

注意:JDK 6 时,String等字符串常量的信息是置于方法区中的,但是到了JDK 7 时,已经移动到了Java堆。所以,方法区也好,Java堆也罢,到底详细的保存了什么,其实没有具体定论,要结合不同的JVM版本来分析。

提到方法区不得不说的就是常量池

补充:方法区不是永久代,只是Hotspot的实现方式而已。

常量池

什么是常量?

常量是指被final修饰的变量,值一旦确定就无法改变。

Class文件中的常量池

常量池主要用于存放两大类常量:字面量和符号引用量(在上面已经介绍过了),字面量相当于Java语言层面常量的概念(如文本字符串,声明为final的常量值等),符号引用则属于编译原理方面的概念

运行时常量池

class文件中的常量池中的内容会在类加载后进入方法区的运行时常量池。

相对于常量池,运行时常量池的重要特征是具有动态性,java并不要求常量只有在编译器才会产生,运行期间也可以将新的常量存放入池中,这种特性用的最多的String类中的intern()方法。

那么变量存放在哪里?

对于字符串:其对象的引用都是存储在栈中的,如果是编译期已经创建好(直接用双引号定义的)的就存储在常量池中,如果是运行期(new出来的)才能确定的就存储在堆中。对于equals相等的字符串,在常量池中永远只有一份,在堆中有多份。

int i1 = 9;
int i2 = 9;
int i3 = 9;
public static final int INT1 = 9;
public static final int INT2 = 9;
public static final int INT3 = 9;

对于基础类型的变量和常量:变量和引用存储在栈中,常量存储在常量池中。

int i1 = 9;
int i2 = 9;
int i3 = 9;
public static final int INT1 = 9;
public static final int INT2 = 9;
public static final int INT3 = 9;

补充:最后一个疑问,jvm怎么调用方法

类加载机制链接部分,在类加载的准备阶段,会为静态字段分配内存,还会构造与该类相关联的方法表

这个数据机构就是java虚拟机实现动态绑定的关键所在。
方法表本质上是一个数据,每个数据元素指向一个当前类以及其祖先类中非私有的实例方法
方法表的两个特质
1,子类方法表中包含父类方法表中的所有方法
2,子类方法在方法表中的索引值,与它所重写的父类方法的索引值相同
索引值
方法调用指令中的符号引用会在执行之前解析成实际引用。对于静态绑定的方法调用而言,实际引用将指向具体的目标方法,对于动态绑定的方法调用而言,实际引用则是方法表的索引值
在执行过程中,java虚拟机将获得调用者的时间类型,并在该时间类型的虚方法表中,根据索引值获得目标方法。这个过程便是动态绑定

JVM运行时数据区域的更多相关文章

  1. 深入理解Java虚拟机 -- 读书笔记(1):JVM运行时数据区域

    深入理解Java虚拟机 -- 读书笔记:JVM运行时数据区域 本文转载:http://blog.csdn.net/jubincn/article/details/8607790 本系列为<深入理 ...

  2. JVM 运行时数据区域划分

    目录 前言 什么是JVM JRE/JDK/JVM是什么关系 JVM执行程序的过程 JVM的生命周期 JVM垃圾回收 JVM的内存区域划分 一.运行时数据区包括哪几部分? 二.运行时数据区的每部分到底存 ...

  3. [jvm]运行时数据区域详解

    了解虚拟机是怎么使用内存的,有助于我们解决和排查内存泄漏和溢出方面的问题.详解java虚拟机内存的各个区域,分析这些区域的作用服务对象以及可能发生的问题. 一.运行时数据区域 java虚拟机在执行ja ...

  4. JVM运行时数据区域详解

    参考文章: <Java Se11 虚拟机规范> <深入理解Java虚拟机-JVM高级特性与最佳实践 第3版>- 周志明 本文基于Java Se 11讲解. 根据<Java ...

  5. JVM 运行时数据区域

    Java虚拟机管理的内存包括以下几个运行时数据区域: 1.程序计数器: 程序计数器是一块比较小的内存空间,是当前线程执行的字节码行号指示器.Java多线程是通过线程轮流切换来实现的,所以每个线程都有一 ...

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

    一.运行时数据区域 1.程序计数器 程序计数器( Program Counter Register) 是一块较小的内存空间, 它可以看作是当前线程所执行的字节码的行号指示器. Java虚拟机的多线程是 ...

  7. JVM运行时数据区域解析

         Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人想出来.      Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同 ...

  8. 轻松认识JVM运行时数据区域(使用思维导图)

    下面是个人阅读周志明编写的深入浅出Java虚拟机做成思维导图的笔记,线条.颜色和图片的视觉印象比起单纯文字笔记好得太多了,文字笔记的枯燥以及硬性记忆我就不再多说,特别对于JVM这块略微有点枯燥的知识, ...

  9. 一. JVM发展史,运行时数据区域,四大引用

    一.JVM的出现 JVM将字节码解释成不同os下的机器指令,有了jvm,java语言在不同平台上运行时不需要重新编译 虚拟机发展史 (1)Sun Classic classic jvm要么采用纯解释器 ...

随机推荐

  1. oracle权限列表

    alter any cluster 修改任意簇的权限 alter any index 修改任意索引的权限 alter any role 修改任意角色的权限 alter any sequence 修改任 ...

  2. python学习1-1

    # 可以支持多个用户登录 (提示,通过列表存多个账户信息) uname = ['wps', 'opp' ] pword = ['] time = 0 while time < 3: u_name ...

  3. JS案例六_1:添加城市

    使用的相关知识点:对子节点的添加:document.appendClild() 文本节点的创建:document.createTextNode() 元素节点的创建:document.createEle ...

  4. 使用HM16.0对视频编码

    1.编译HM16.0源码: 步骤参照:https://www.vcodex.com/hevc-and-vp9-codecs-try-them-yourself/(可设置pq等参数) [编译过程中遇到l ...

  5. centos7初上手3-安装apache服务

    前两篇学习安装了mysql服务器,tomcat服务,这篇文章学习安装apache服务 1.执行yum install httpd,安装完成后查看httpd rpm -qa|grep httpd 2.新 ...

  6. 6 python高级数据处理和可视化

    6.2. pyplot作图 1.折线图和散点图 t = np.arange(0,4,0.1) plt.plot(t,t,'o',t,t+2,t,t**2,'o') plt.show() 2.柱线图 p ...

  7. 指导手册 07 安装配置HIVE

    指导手册 07 安装配置HIVE   安装环境及所需安装包: 1.操作系统:centos6.8 2.四台虚拟机:master :10.0.2.4, slave1:10.0.2.5,slave2:10. ...

  8. springboot源码之(内嵌tomcat)

    server---service----engine----host-----context---wrapper---servletStandardServer---StandardService-- ...

  9. 深圳奥特迅现金流量——RESSET数据库

    现金流不好,很多年都是负数.到公司官方网站上收集信息,拳头产品有矩阵柔性充电堆,主要盈利产品有电源和电源管理系统.还承担了深圳市的充电桩交钥匙项目. 下面是它这些年的股价,在大牛市的时候也上升至五十几 ...

  10. 牛客练习赛 43 B-Tachibana Kanade Loves Probability

    链接:https://ac.nowcoder.com/acm/contest/548/B 题目描述 立华奏在学习初中数学的时候遇到了这样一道大水题: “设箱子内有 n 个球,其中给 m 个球打上标记, ...