1、程序计数器(Program Counter Register)

        线程独有,每个线程都有自己的计数器;由于CPU的任意时刻只能执行所有线程中的一条,所以需要使用程序计数器来支持JVM的并发;另外字节码解释器读取下一行指令、分支、循环、跳转、异常处理等等逻辑都依赖于程序计数器。程序计数器是JVM唯一不存在OutOfMemoryError的区域。

2、Java虚拟机栈(Java Virtual Machine Stacks)

        线程独有,用于保存线程相关的栈帧(@注释1);生命周期与线程相同,线程中,方法执行的过程等同该方法对应栈帧从入栈到出栈的过程,如果方法执行过程中调用了其它方法,那么同样的道理,方法内部调用的其它方法的栈帧也会入栈,以此类推,直到当前方法执行完,然后从虚拟机栈中出栈即代表一个方法完整的执行过程。

Java虚拟机栈内存大小即可固定,也支持动态拓展(在JVM运行内存的范围内):

(1)当固定大小情况下,线程请求分配的栈容量大于Java虚拟机栈最大容量时,抛出异常:StackOverFlowError。

(2)当可拓展时,如果在拓展过程中,无法申请到足够的内存时,抛出异常:OutOfMemoryError(比如:JVM运行内存被占满,此时已经无处可以申请内存了)。

3、本地方法栈(Native Method Stack)

        类似上述Java虚拟机栈,放入Java虚拟机栈中的是Java方法的栈帧;而本地方法栈中的内容是native方法(@注释2)的栈帧,他为native方法服务。

例如:java.lang.String.intern() 和  java.lang.Object.hashCode()方法的定义如下:

public native String intern();
public native int hashCode();

4、Java堆(Java Heap)

       Java堆是线程共享的,它是JVM中占用内存空间最大的部分,它的作用是存放Java对象实例,几乎所有的Java对象都从堆中分配内存;因为Java堆存放了大量对象实例,所以这里也是垃圾回收发生的主要场所;Java堆内存大小即可设为固定值,也可以动态拓展,Java堆可以处于非连续的物理内存上(大学的某门课讲过原理,逻辑上连续即可)。

5、方法区(Method Area)

       (1) 基本概念:同Java堆,方法区也是线程共享;方法区保存JVM加载的:类的信息、常量、静态变量、即时编译器编译后的代码,等数据;Java虚拟机规划中对方法区限制较少,是否受垃圾回收器管理是可选的,大小可固定或可拓展,可以存在于不联系的内存空间上。

(2) 关于HotSpot虚拟机:Java 7之前,方法区与Java堆共享内存,Java堆被划分为:青年代、老年代、永久代,其中永久代即指方法区,同样此时方法区被垃圾回收器管理;到了Java 8,HotSpot虚拟机改变了实现方式,方法区分配的内存被移至虚拟机外,此时称呼其为元空间,不再与Java堆共享内存,也不再被垃圾回收器管理。

(3) 运行时常量池

a 基本概念:位于方法区,它是每一个类或接口中的,常量池表,运行时的表示形式;每一个运行时常量池(对应 类/接口),在加载 类/接口时被创建并分配到方法区中。

b 常量池作用:存放编译器生成的字面量和符号引用,当虚拟机运行时,从常量池获取字面量或者符号引用,在类创建或者运行时,映射到具体的内存中。

c 字面量(常量):字符串   ||   final   变量

d 符号引用:类/接口的全限定名  ||    字段名称及其描述符   ||   方法名称及其描述符

本文仅限于JVM各个组成部分即基本介绍,不深入讨论原理,旨于深入探究JVM前建立相关概念模型。

* 拓展及注释

1、栈帧

        基本概念:在JAVA虚拟机栈中使用,用于支持JVM进行方法调用和方法执行的数据结构(栈帧就是虚拟栈中的一个元素),每个方法执行时都会创建一个栈帧,它包括:局部变量表、操作数栈、动态链接、方法返回地址等。对于JVM执行引擎来说,在活动的线程中,只有处于栈顶的栈帧是有效的,所有字节码指令都只对作用在当前栈帧关联的方法上。

(1)局部变量表:一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量,局部变量表的容量以  变量槽(Slot)  为单位;每个Slot的大小与JVM平台有关,一般可以存放32位以内的数据类型:8种基本数据类型,以及  对象应用(reference)和returnAddress(方法返回地址)。对于  对象应用(reference),JVM必须做到能够直接或间接查找到对象在JAVA堆中的数据存储地址起始索引,以及能查找到对象所属数据类型在方法区中存储的类型信息;

(2)操作数栈:它是一个LIFO栈,操作数栈中的每一个元素都可以是任意的Java数据类型,栈的最小容量单位为32bite,32位的数据类型栈一个容量单位,64位数据类型占2个容量单位。JVM引擎执行的实质可以理解成:从操作数栈栈顶提取元素,然后执行指令,并把执行结果压入栈中的过程。

(3)动态链接:

前提条件(背景):每一个栈帧都会持有一个指向运行时常量池中该栈帧所属的方法引用,持有该引用的目的是为了支持方法调用过程中的动态链接。字节码(Class文件中,可以借助工具查看编译后的Class文件中的字节码指令)  的方法调用指令就是以Class文件常量池中的符号引用作为参数的;

动态链接:上述符号引用中,有的符号引用会在每次运行期间转化为直接引用,该类引用称为动态链接;

静态链接:相较于动态链接,对于静态链接,符号引用会在类加载  或   第一次使用的时候就转化为直接引用,而不是每次执行时去转化为直接引用。

(4)方法返回地址:方法执行完有两种方式退出方法,其一为方法执行过程中遇到任意一个方法返回的字节码指令,然后将相关结果返回给方法的调用者。其二,方法执行碰到异常,并且异常没有被捕获处理时推出方法。方法退出,即代表当前     (栈)帧   出栈,后续将会执行当前方法的调用者(上层方法)所对应的   (栈)帧   后续指令,那么对应的操作即为:恢复调用者对应  栈帧  的局部变量表和操作数栈,把当前方法的返回值压入调用者方法对应栈帧的操作数栈中,调用PC计数器的值并使之执行当前方法调用指令的下一条指令(当前方法执行完,挫骨扬灰,只留下了舍利供调用者使用,当然也可能直接烧成灰了啥也没有(无返回值))。

2、native方法(本地方法):

        可以理解为java调用非Java代码实现的方法,的接口。众所周知,Java中很多东西都是其它语言实现的(例如C语言),使用native方法(本地方法)的原因如下:

(1)与java环境外交互:

                有时java应用需要与java外面的环境交互。这是本地方法存在的主要原因,你可以想想java需要与一些底层系统交换信息时的情况。本地方法正是这样一种交流机制:它为我们提供了一个非常简洁的接口,而且我们无需去了解java应用之外的繁琐的细节。

        (2)与操作系统交互:

                JVM支持着java语言本身和运行时库,它是java程序赖以生存的平台,它由一个解释器(解释字节码)和一些连接到本地代码的库组成。然而不管怎 样,它毕竟不是一个完整的系统,它经常依赖于一些底层(underneath在下面的)系统的支持。这些底层系统常常是强大的操作系统。通过使用本地方法,我们得以用java实现了jre的与底层系统的交互,甚至JVM的一些部分就是用C写的,还有,如果我们要使用一些java语言本身没有提供封装的操作系统特性时,我们也需要使用本地方法。

《深入理解JAVA虚拟机》(一) JVM 结构 + 栈帧 详解的更多相关文章

  1. 【转载】深入理解Java虚拟机笔记---运行时栈帧结构

    栈帧(Stack Frame)是用于支持虚拟机进行方法调用和方法执行的数据结构,它是虚拟机运行时数据区的虚拟机栈(Virtual Machine Stack)的栈元素.栈帧存储了方法的局部变量表,操作 ...

  2. 深入理解java虚拟机(八)类加载过程详解

    类从被加载到虚拟机内存开始,到卸载出内存为止,它的整个生命周期包括:加载(Loading).验证(Verification).准备(Preparation).解析(Resolution).初始化(In ...

  3. 《深入理解Java虚拟机:JVM高级特性与最佳实践》【PDF】下载

    <深入理解Java虚拟机:JVM高级特性与最佳实践>[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230062566 内容简介 作为一位 ...

  4. 读书笔记-《深入理解Java虚拟机:JVM高级特性与最佳实践》

    目录 概述 第一章: 走进Java 第二章: Java内存区域与内存溢出异常 第三章: 垃圾收集器与内存分配策略 第四章: 虚拟机性能监控与故障处理 第五章: 调优案例分析与实战 第六章: 类文件结构 ...

  5. Java中堆内存和栈内存详解2

    Java中堆内存和栈内存详解   Java把内存分成两种,一种叫做栈内存,一种叫做堆内存 在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配.当在一段代码块中定义一个变量时,ja ...

  6. 深入理解Java虚拟机之JVM垃圾回收随笔

    1.对象已经死亡? 1.1引用计数法:给对象中添加一个引用计数器,每当有一个地方引用他时,计数器值就加1:当引用失效时,计数器值就减1:任何时刻计数器都为0的对象就是不可能再被使用 的.但是它很难解决 ...

  7. Java 虚拟机系列二:垃圾收集机制详解,动图帮你理解

    前言 上篇文章已经给大家介绍了 JVM 的架构和运行时数据区 (内存区域),本篇文章将给大家介绍 JVM 的重点内容--垃圾收集.众所周知,相比 C / C++ 等语言,Java 可以省去手动管理内存 ...

  8. java虚拟机规范-运行时栈帧

    前言 java虚拟机是java跨平台的基石,本文的描述以jdk7.0为准,其他版本可能会有一些微调. 引用 java虚拟机规范 java虚拟机规范-运行时数据区 java内存运行时的栈帧结构 java ...

  9. 深入理解Java虚拟机:JVM高级特性与最佳实践

    第一部分走近Java第1章走近Java21.1概述21.2Java技术体系31.3Java发展史51.4Java虚拟机发展史91.4.1SunClassicExactVM91.4.2SunHotSpo ...

  10. 深入理解Java虚拟机之JVM内存布局篇

    内存布局**** ​ JVM内存布局规定了Java在运行过程中内存申请.分配.管理的策略,保证了JVM的稳定高效运行.不同的JVM对于内存的划分方式和管理机制存在部分差异.结合JVM虚拟机规范,一起来 ...

随机推荐

  1. [转帖]pod容器开启pid限制

    https://zhdya.gitee.io/zhdya/archives/   cgroup中对pid进行了隔离,通过更改docker/kubelet配置,可以限制pid总数,从而达到限制线程总数的 ...

  2. 【转帖】MySQL 8.0 hash join有重大缺陷?

    我并不这么看. 友情提醒:本文建议在PC端阅读. 徐春阳老师发文爆MySQL 8.0 hash join有重大缺陷. 文章核心观点如下:多表(比如3个个表)join时,只会简单的把表数据量小的放在前面 ...

  3. [转帖]美国出口管制条例(EAR)简介

    https://zhuanlan.zhihu.com/p/87962305 第一节.美国出口管制法律体系 下述一系列法律.法规及规则,构成美国完整的出口管理制度,是美国各相关执法部门执法的主要法律依据 ...

  4. ARM 平台Docker运行RabbitMQ 以及迁移的简单办法

    公司网络很垃圾. 可以使用vps 进行下载和打包  放到 公司的机器上面进行使用. 1. 搜索有没有可用的镜像. [root@JNXLH ~]# docker search rabbitmq |gre ...

  5. [转贴]使用dbstart 和dbshut 脚本来自动化启动和关闭数据库

    使用dbstart 和dbshut 脚本来自动化启动和关闭数据库 https://www.cnblogs.com/snowers/p/3285281.htmldbshut 和 dbstart 使用db ...

  6. K3S +Helm+NFS最小化测试安装部署只需十分钟

    作者:郝建伟 k3s 简介 官方文档:k3s 什么是k3s k3s 是一个轻量级的 Kubernetes 发行版 它针对边缘计算.物联网等场景进行了高度优化. k3s 有以下增强功能: 打包为单个二进 ...

  7. C#对象属性浅拷贝和深拷贝

    对象属性和字段拷贝的几种方式 微软提供了浅拷贝 对于值类型,修改拷贝的值不会影响源对象 对于引用类型,修改拷贝后的值会影响源对象,但string特殊,它会拷贝一个副本,互相不会影响 自己实现深拷贝,我 ...

  8. ILRuntime性能测试

    我们公司有一个Unity原生开发语言C#写的项目,目前已经在安卓测试过多次,上架IOS在考虑热更,所以对ILRuntim进行性能测试,在测试过程中已经按照官方文档进行了CLR绑定和生成Release的 ...

  9. c++基础之变量和基本类型

    之前我写过一系列的c/c++ 从汇编上解释它如何实现的博文.从汇编层面上看,确实c/c++的执行过程很清晰,甚至有的地方可以做相关优化.而c++有的地方就只是一个语法糖,或者说并没有转化到汇编中,而是 ...

  10. C# 字符与字符串操作

    在C#中,字符和字符串是两个重要的数据类型,有许多内置的方法可以处理字符和字符串.这些方法是非常有用的,可以帮助开发人员更方便.更高效地处理文本数据. 格式化字符串: using System; us ...