上面已经聊过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. 面向对象DAO模式

    DAO模式编写数据访问层代码步骤? 1.  接口 增.删.改.查的方法 方法的返回类型为泛型集合 Int rows=select语句的条数 If(rows>0) 方法的返回类型为泛型集合 If( ...

  2. K2百家讲坛 | 越秀地产:K2为房企数字化转型带来更多可能

    随着数字化经济时代的到来,房地产行业逐渐形成了新的竞争和市场格局,房企要在此背景下实现稳步发展,需要由原本的粗放式管理逐渐向集团性管理.精细化管控转变,这对房企的经营发展战略和业务管理方式都提出了不小 ...

  3. http协议与https协议的前世今生

    一.Http与Https的区别: HTTP 的URL 以http:// 开头,而HTTPS 的URL 以https:// 开头 HTTP 是不安全的,而 HTTPS 是安全的 HTTP 标准端口是80 ...

  4. Failed to start bean 'stompBrokerRelayMessageHandler'; nested exception is java.lang.NoClassDefFoundError: reactor/io/codec/Codec

    最新版本的Spring需要reactor 2.0,看看你的POM有一个明确的1.1.6依赖. 解决: <dependency> <groupId>org.projectreac ...

  5. 电脑小白和ta的小白电脑——JAVA开发环境

    JAVA开发环境的搭建有一点点复杂,不过一步一步来一般不会出错. (一)下载JDK 首先我们需要下载java开发工具包JDK,可以通过官网下载:http://www.oracle.com/techne ...

  6. grep用法

    正则表达式只是一种表示法,只要工具支持这种表示法, 那么该工具就可以处理正则表达式的字符串.vim.grep.awk .sed 都支持正则表达式,也正是因为由于它们支持正则,才显得它们强大:在以前上班 ...

  7. Qt笔记之QGADGET

    QGADGET宏类似于Q_OBJECT宏,是一个万能容器,至于这个宏所实现的功能,我也不懂,Q_OBJECT宏的功能到时了解一些,我想他们应该差不多,要想使用从Q_OBJECT继承来的类,就得在一开始 ...

  8. 新版ios证书的申请

    现在IOS不再开放提供测试证书了,整理一个申请证书的流程. 1. 申请应用的id 链接地址 https://developer.apple.com/登陆开发者中心,在account界面点击红框里面得区 ...

  9. python的标准数据类型

    python有5种标准的数据类型 1. number(数字) int(有符号的整形) long(长整[也可以代表八进制和16进制]) float(浮点型) complex(复数类型) 2.string ...

  10. Holer实现oracle数据库外网访问

    外网访问内网Oracle数据库 内网主机上安装了Oracle数据库,只能在局域网内访问,怎样从公网也能访问本地Oracle数据库? 本文将介绍使用holer实现的具体步骤. 1. 准备工作 1.1 安 ...