深入理解JVM内部结构

深入理解JVM虚拟机第十七篇:虚拟机栈中栈帧的内部结构 本文是深入理解JVM虚拟机第十七篇,详细讲解了虚拟机栈中栈帧的内部结构 阅读详情
 这篇文章主要是解释java虚拟机(JVM)的内部结构。下图显示了符合Java SE 7 版本的Java虚拟机规范的一个典型JVM中的关键内部组件。


     图中显示的组件将会在下面两部分中进行逐一的解释。第一部分涉及JVM为每一个线程都会创建的组件;第二部分则是独立于线程进行创建的组件。

1. Thread
     Thread是一个程序中的一个执行线程。JVM允许一个应用程序有多个执行线程并发运行。在Sun的Hotspot JVM中,Java线程与本地操作系统线程间存在一个直接的一一映射。JVM先为Java线程准备好所有的状态,如线程局部存储、分配缓冲区、同步对象、栈和程序计数器,之后对应的本地线程被创建。Java线程终止以后其本地线程将会被回收利用,由操作系统负责调度所有的线程并将它们分派到可用的CPU。一旦本地线程已经初始化完成,则会调用Java线程的run()方法,当run()方法返回时,未捕获的异常将被处理,之后本地线程判断JVM是否需要终止运行(如此线程是最后一个非守护线程)。当线程终止以后,本地线程及Java线程占用的所有资源都会被释放。

1.1 JVM系统线程
    如果你曾使用jconsole或其它的一些调试工具,也许你会注意到JVM中有许多的线程运行在后台。这些运行的后台线程,除了main线程以外,都是作为调用public static void main(String [])的一部分被创建,此外,还有一些是被main线程所创建。以Sun的Hotspot JVM为例,主要的后台系统线程有:

(1) VM Thread 
     此线程用于等待请求JVM到达一个“安全点”的操作的出现。之所以所有这类操作需要在一个单独的线程——VM Thread中进行,是因为它们都要求JVM处于“安全点”,当JVM位于“安全点”时,不能对heap执行修改操作。VM Thread执行的操作类型是会“stop-the-world”的垃圾回收、线程堆栈转储、线程挂起和偏向锁撤销。
注:stop-the-world,也即当执行此操作时,Java虚拟机需要停止运行。

(2) Periodic task thread(周期任务线程)
     此线程负责用于调度周期性操作的执行的定时事件。

(3) GC threads(垃圾回收线程)
      这些线程用于支持JVM中进行的不同类型的垃圾回收活动。


(4) Compiler threads
      这些线程在运行时将字节码编译成本地代码。

(5) Signal dispatcher thread(信号分发线程)
      此线程负责接收发送给JVM进程的信号,处理信号,根据系统设置调用合适的JVM方法。

1.2 Per Thread
     每一个执行的线程都具有下列组件:
(1) 程序计数器(program Counter,PC)
    除非是本地代码,否则PC指向当前指令(也即opcode)的地址。如果当前方法是本地的,则PC是未定义的。所有的CPU都有一个PC,一般情况下,PC会在每一个指令之后进行递增,以保存下一个执行指令的地址。JVM使用PC来记录当前指令执行的位置,PC实际上指向了方法区的一个内存地址。

(2) 栈(Stack)
   每个线程都有自己的栈,栈为线程中执行的每个方法保存了一个对应的帧(Frame)。栈是后进先出(LIFO)的数据结构,因此当前执行的方法总是位于栈的顶端。当调用一个方法时,为其创建一个新的帧并压栈,当方法正常返回或者是由于执行期间抛出了未捕获的异常而退出时,其对应的帧将被删除(也即出栈)。除了执行帧的压栈与出栈,无法对栈进行其它的直接操作,因此帧对象也许是在堆(Heap)中进行内存分配,它们的内存也就无需是连续的。

(3) 本地栈(Native Stack)
    并非所有的JVM都支持本地方法,然而,那些支持的JVM一般会为每个线程创建本地方法栈。如果JVM是使用“C链接”模型实现Java本地调用(JNI)的,则本地栈将是一个C栈。在这种情况下,本地栈中参数及返回值的顺序将与典型的C程序是一致的。一个本地方法一般会调回JVM,并调用Java方法,此类从本地方法到Java方法调用发生于正常的Java栈中,线程会离开本地栈,并在Java栈中为方法创建一个新的帧。

(4)栈的限制(Stack Restrictions)
栈可以是动态的,也可以是固定大小的。如果一个线程要求超过允许的大小的栈,则JVM会抛出StackOverflowError。如果线程要求创建一个新的帧,但是系统没有足够内存进行分配,则JVM会抛出OutOfMemoryError。

(5) 帧(Frame)
原文内容与栈部分大致一致,不冗述。
每个帧中包含有:1. 局部变量数组;2. 返回值;3. 操作对象栈;4. 到方法所属类的运行时常量池的引用。

(6) 局部变量数组(Loca Variables Array)
   局部变量数组中包含了方法运行期间使用到的所有变量,包括到this变量的引用、所有的方法参数及其它方法中定义的局部变量。对于类方法(静态方法),方法参数从“零”开始,而对于实例方法,“零”位置预留给this变量。
一个局部变量可以是:
  • boolean
  • byte
  • char
  • long
  • short
  • int
  • float
  • double
  • reference
  • returnAddress
除了long和double,所有的类型都在局部变量数组中占据一个位置,long及double则占用两个连续的位置(slot),由于它们是双倍的宽度,也即64位大小。

(7) 操作对象栈
    操作对象栈在字节码指令执行期间使用,作用类似于CPU使用的一般用途的寄存器。大多数的JVM操纵操作对象栈的方式有:压栈、出栈、复制、交换、通过执行某一操作产生或消耗成数值。因此,在字节码中,在局部变量数组与操作对象栈之间移动数值的指令出现的次数很多。例如,一个简单的变量就需要两条与操作对象栈进行交互的字节码。
     
[java]  view plain copy
  1. int i;  
     编译以后的字节码如下:
     
[java]  view plain copy
  1. 0: iconst_0 // Push 0 to top of the operand stack  
  2. 1: istore_1 // Pop value from top of operand stack and store as local variable 1  

(8) 动态链接
       每个帧包含了一个到运行时常量池的引用。此引用指向当前执行的方法对应的类的常量池,用于辅助支持动态链接功能。
     当一个类被编译以后,所有到变量及方法的引用都被存储到类的常量池中作为一个符号引用。一个符号引用是一个逻辑引用而不是直接指向物理内存地址的引用。JVM的实现可以自由选择何时解析符号引用,可能的选择有:类文件被验证时亦或是被加载以后,这类方案被称为是急切的(eager)或静态的(static)解析;还有一种被称为懒加载或延时加载方案,它是在符号引用第一次被使用时进行解析。然而,JVM必须要表现得像是当引用第一次被使用时才进行解析,并且此时需要抛出任何的解析错误。
    绑定是由符号引用标识的域、方法和类被直接引用替换的过程,此过程只发生一次。如果指向类的符号引用还没有被解析则此类会被加载。每一个直接引用都被存储为一个相对偏移值,以与变量或方法的运行时位置关联的存储结构作为基准。

1.3 Shared Between Threads
(1) 堆(Heap)
  堆用于运行时分配类实例及数组。数组及对象无法存储在栈中,因为帧在创建以后,其大小就无法再改变。帧中只能存储指向堆中对象或数组的引用。与简单变量与在局部变量中的引用不同,数组对象总是存储在堆中,因此当方法退出时,它们没有被移除,对象只能被垃圾收集器移除。
     为了支持垃圾回收,堆被分为三个部分:
  • Young Generation(年轻代),通常被分为Eden和Survivor
  • Old Generation(老年代,也叫Tenured Generation)
  • Permanent Generation
(2) 内存管理
      对象及数组不会被显示释放,垃圾回收器会自动回收它们。
此过程如下:
1. 新的对象和数组被创建并放到年轻代中;
2. 一次小的垃圾收集会在年轻代上执行,如果对象存活下来,则它们将被从eden空间移动到survivor空间;
3. 主垃圾收集(Major)执行,它会引起应用线程停止运行,也即stop-the-world,同时会在不同的“代”中移动对象。经过此次垃圾回收后,如果对象仍然存活,则它们会被从年轻代移动到老年代。
4. 在每次老年代被回收时永久代也被回收,当任何一个空间满时,它们都会被回收。

(3) 非堆内存
   从逻辑上考虑,被认为是JVM结构的一部分的对象将不会在堆中进行创建。非堆内存包括有:1.包含方法区及interned字符串的永久代;2. 代码缓存,用于编辑与存储已经被JIT编译器编译为本地代码的方法。

(4) 即时编译
Java字节码采用解释执行方式,因此它没法像直接在JVM所在的主机上执行本地代码那么快。为了提高性能,Oracle Hotspot VM寻找字节码中被周期地执行的“热区域”,并将它们编译为本地代码。本地代码被存储到非堆内存的代码缓存中,通过这样的方式,Hotspot VM尝试选择最合适的方式来权衡编译代码花费的额外时间与执行解释代码花费的额外时间。

(5) 方法区(Method Area)
方法区中存储了每个类的元信息,如:
  • 类加载器引用
  • 运行时常量池
    • 数值常量
    • 字段引用
    • 方法引用
    • 属性值
  • 字段数据
    • 每个字段
      • 名称
      • 类型
      • Modifiers
      • 属性值
  • 方法数据
    • 每个方法
      • 名称
      • 返回类型
      • 参数类型
      • Modifiers
      • 属性值
  • 方法代码
    • 每个方法
      • 字节码
      • 操作对象栈大小
      • 局部变量大小
      • 局部变量表
      • 异常表
        • 每个异常处理器
          • 起始点
          • 结束点
          • 处理器代码的PC偏移值
          • 捕抓的异常类的常量池索引
   所有的线程共享相同的方法区,因此方法区数据的存取及动态链接的过程必须是线程安全的。如果两个线程都企图存取同一个类中的字段或方法,但是,此类还没有被加载,则它必须只被加载一次,并且线程必须等到类被加载完成以后才能继续执行。

(6) 类文件结构
       一个编译完成的类文件包含以下的结构:
[java]  view plain copy
  1. ClassFile {  
  2.     u4          magic;  
  3.     u2          minor_version;  
  4.     u2          major_version;  
  5.     u2          constant_pool_count;  
  6.     cp_info     contant_pool[constant_pool_count – 1];  
  7.     u2          access_flags;  
  8.     u2          this_class;  
  9.     u2          super_class;  
  10.     u2          interfaces_count;  
  11.     u2          interfaces[interfaces_count];  
  12.     u2          fields_count;  
  13.     field_info      fields[fields_count];  
  14.     u2          methods_count;  
  15.     method_info     methods[methods_count];  
  16.     u2          attributes_count;  
  17.     attribute_info  attributes[attributes_count]; 
  18.  
转载: http://blog.youkuaiyun.com/shi1122/article/details/8921315

使用3dmax Morpher制作Unity表情动画 关于游戏人物的面部表情动画 方案一:如果面部骨骼数丰富的话,可以直接做骨骼动画 方案二:采用变形器(3dmax是Morpher,maya是blendshape)修改相应通道的权重值来做表情动画 本文简述方案二的做法。 说明:本文截图中3dsMax版本为2017。笔者第一次使用3dsMax,欢迎指正。 3dmax中导入人物模型,选择需要变形的对象,即head。当前对象附带skin信息。 ... 阅读详情

相关推荐

STM32F4与LAN8720硬件连接避坑指南:从原理图到RMII信号完整性的实战解析

本文深入解析了STM32F4与LAN8720以太网连接的硬件设计要点与常见陷阱。重点剖析了电源上电时序、复位电路设计、RMII接口配置等关键环节,并提供了从原理图设计到PCB布局、信号完整性调试的完整实战指南,帮助硬件工程师规避设计风险,确保以太网通信的长期稳定运行。

weixin_29189003的博客 211

JVM内存结构

JVM内存结构 JVM的内存结构大致分为五个部分,分别是程序计数器、虚拟机栈、本地方法栈、堆和方法区。除此之外,还有由堆中引用的JVM外的直接内存。 下面将展开讲解这五个部分。 程序计数器 程序计数器(Program Counter Register),用于记录下一条JVM指令的执行地址(如果正在执行的是本地方法则为空)。例如下图中的JVM指令,当我执行到地址为0的指令时,程序计数器就会存下下一条指令的地址,也就是地址3。 要注意的是,程序计数器时线程私有的,每一个线程都有一个程序计数器,只有这么设计,

weixin_41812379的博客 1万+

ROS 2 Slam Toolbox实战:从零跑通2D激光建图

SLAM(同步定位与地图构建)是移动机器人实现自主导航的基础技术,其核心在于通过传感器数据实时估计位姿并构建环境栅格地图。slam_toolbox作为ROS 2 Humble及后续LTS版本官方主推的2D SLAM后端,采用图优化+闭环检测架构,兼顾实时性、鲁棒性与工程可维护性。相比cartographer和hector_slam,它原生支持ROS 2、参数精简、诊断友好,特别适合硬件资源有限、缺乏IMU或深度相机的差速机器人平台。本文聚焦真实部署场景,覆盖RPLIDAR等常见2D激光雷达与TurtleBo

weixin_30596165的博客 356

JVM字节码指令详解

在我们日常的Java开发中,我们的IDE开发工具会自动的通过编译器将Java代码编译成字节码文件,最后通过JVM来执行这些字节码文件。在这个过程中,一个重要的环节就是Java字节码。Java字节码是Java虚拟机(JVM)可以执行的指令集,它在一定程度上代表了Java的跨平台特性,因为不同的操作系统平台上的JVM都可以执行相同的Java字节码。因此,深入理解Java字节码对于掌握Java的运行机制是非常重要的。在本篇博文中,我将对JVM字节码的基础知识、指令类型、命名规则以及优化策略等方面进行详细的讲解。

日拱一卒无有尽,功不唐捐终入海 1378

【C++】ROS:ROS1环境配置与基础示例

ROS1环境配置与基础示例

DevFrank的博客 2103

Fiori Elements 的 Adapting the UI: Analytical List Page 全解析与实战

摘要:本文详细介绍了如何通过SAP Fiori elements的UI Adaptation功能对Analytical List Page(ALP)进行细粒度适配。重点讲解了页头过滤区、图表区域、表格区域等关键组件的可配置属性,包括过滤区折叠/固定、图表类型限制、表格滚动阈值等实用功能。文章强调这些适配均可通过可视化工具完成,无需修改业务代码,并提供了典型场景的实践清单。适用于SAP Fiori elements for OData V2项目,建议配合SAP Fiori tools的Adaptation E

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 432

JVM(11)_读懂字节码指令

文章目录1. 加载与存储指令1.1 概述1.2 局部变量压栈指令1.3 常量入栈指令1.4 出栈装入局部变量表指令2. 算数指令3. 比较指令 1. 加载与存储指令 1.1 概述 作用: 加载和存储指令用于将数据从栈帧的局部变量表和操作数栈之间来回传递 忘记局部变量表和操作数栈相关内容可看! 常用指令 [局部变量压栈指令]将一个局部变量加载到操作数栈:xload、xload_(其中x为i、l、f、d、a,n 为 0 到 3 ) [常量入栈指令] 将一个常量加载到操作数栈: bipush、 sipush、l

weixin_48922154的博客 1100

Python从0到100完整学习指南(必看导航)

想做这件事情很久了,这次我更新了自己所写过的所有博客,汇集成了Python从0到100,共一百节课,帮助大家一个月时间里从零基础到学习Python基础语法、Python爬虫、Web开发、 计算机视觉、机器学习、神经网络以及人工智能相关知识,成为学业升学和工作就业的先行者!

拥有百余位万粉技术博主、200余位可合作代发博主,私域技术社群规模达千人,商务合作私信 6万+

JVM:Java指令源码opcode

JVM:Java指令源码opcode 关键词 Java 字节码是沟通 JVM 与 Java 程序的桥梁 指令( opcode)由操作码和操作数组成 JVM 翻译字节码( 将 opcode + 操作数翻译成机器代码、 JIT即时编译 ) 一、 Java 程序的执行过程 Java 程序的执行过程 图示: 其中,调用了System.out 等模块,是 JRE 里提供的类库。 使用 JDK 的工具 javac 进行编译后,会产生 HelloWorld 的字节码。 我们一直在说 Java 字节码是沟通 JV

chuanchengdabing的博客 1447

【教程4>第3章>第1节】通信系统高阶调制解调概述

高阶调制(High Order Modulation)是一种先进的数字调制技术,旨在通过增加每个符号携带的信息比特数来提高无线通信系统的数据传输速率和频谱效率。这种技术特别适用于具有较高信噪比(Signal-to-Noise Ratio, SNR)的通信环境,例如卫星通信、光纤通信以及一些高质量的无线通信链路。在数字通信中,调制是将数字信号(比特流)转换为适合在物理信道上传输的模拟信号的过程。高阶调制通过使用更多的信号状态或星座点来表示不同的比特组合,从而在一个符号周期内传输更多的信息。

FPGA/MATLAB学习教程/源码/项目合作开发 1702

《企业AI能力地图构建:AI应用架构师的关键秘籍》

构建企业AI能力地图是企业在AI时代实现战略转型和创新发展的关键举措,它需要从评估企业当前AI能力出发,全面了解技术储备、数据资产和人才队伍的现状。将企业业务战略转化为具体的AI应用场景,并进行优先级排序,是确保AI应用能够为企业带来实际价值的重要步骤。通过深入理解业务战略和挖掘应用场景,企业可以找准AI应用的切入点,提高投资回报率。

AI架构全栈开发实战笔记 631

jvm整体架构图文详解

今天学习了jvm三大组成部分(jvm类加载器,jvm内存结构,jvm执行引擎)的内存结构,现在把学习笔记总结记录一下,当作复习吧。 1.jvm的概念 JVM(虚拟机):指以软件的方式模拟具有完整硬件系统功能、运行在一个完全隔离环境中的完整计算机系统 ,是物理机的软件实现。 jvm和VMware,Virtual Box等虚拟机一样,都是运行在操作系统之上的计算机系统。 首先我们来看看jvm的整体架构的划分: 大家在留意内存结构的时候是不是发现,本地方法栈,程序计算器和java栈颜色一样的,而方法区和堆却不

bhegi_seg的博客 3839

【keil5和STC-ISP】保姆级下载安装教程

点击下载中的产品下载。然后就会看到如下界面:可以看到,提供了针对不同芯片架构的四套独立开发工具。:你使用的51单片机,其核心就是。C51套件里的编译器是专门为这个架构优化的。:如果安装了MDK-Arm,你在创建新项目时将像“AT89C51”这样的51系列芯片型号,无法进行开发。进入如下界面:双击下载 → 双击运行安装 → 同意协议并下一步 → 使用默认安装路径 → 完成安装。

深耕CV 1640

深入理解JVM虚拟机_4 JVM内部结构分析-栈

深入理解JVM虚拟机_4 JVM内部结构分析-栈

田宝宝的博客 473

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

深入理解JVM内部结构(转)

图中显示的组件将会在下面两部分中进行逐一的解释。第一部分涉及JVM为每一个线程都会创建的组件;第二部分则是独立于线程进行创建的组件。 1. Thread Thread是一个程序中的一个执行线程。JVM允许一个应用程序有多个执行线程并发运行。在Sun的Hotspot JVM中,Java线程与本地操作系统线程间存在一个直接的一一映射。JVM先为...

weixin_30708329的博客 78

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

【深入理解JVM】Java对象创建过程和对象内部结构

一、对象的创建过程 二、对象的内部结构(内存分配) 1、对象头 hashcode GC分代年龄 线程编号 锁编号 时间戳 引用计数 … 2、实例数据   存储所定义的各种类型字段内容,无论是从父类继承下来,还是在子类中定义的,都需要记录起来。 3、对齐填充   起着占位符的作用,实例数据起始地址必须是8字节的整数倍,(对像的大小必须是8字节的整数倍)。 三、对象的访问   通过栈上的refe...

程序员云帆哥的博客 1077

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

深入理解JVM内部结构(续)

如果你编译下面这个简单的类: package org.jvminternals; public class SimpleClass { public void sayHello() { System.out.println("Hello"); } }之后你可以通过运行如下的javap命令,获得字节码信息,如: javap -v -p -s

看看写写,记录所学,权当笔记の 1589

深入理解JVM之三:运行时数据区内部结构

内存是十分重要的系统资源,是硬盘和CPU的中间仓库及桥梁,承载着操作系统和应用程序的实时运行,JVM内存布局规定了java在运行过程中内存申请,分配,管理的策略,保证了JVM的高效稳定运行,不同的JVM对于内存的划分方式和管理机制存在着部分差异。结合JVM虚拟机规范,来探讨下经典的JVM内存布局。 JVM定义了若干种程序运行期间会使用到的运行时数据区,其中有一些会随着虚拟机启动而创建,随着虚拟机退出而销毁。另外一些则是与线程一一对应的,这些与线程对应的数据区域会随着线程的开始和结束而创建和销毁。 线程私有

我的java进阶之路 228

深入理解JVM虚拟机_5 JVM内部结构分析-方发区(元空间)

深入理解JVM虚拟机_5JVM内部结构分析-方发区(元空间)

田宝宝的博客 208

转:深入理解jvm

深入理解JVM 原文链接:http://www.cubrid.org/blog/dev-platform/understanding-jvm-internals 每个使用Java的开发者都知道Java字节码是在JRE中运行(JRE: Java 运行时环境)。JVM则是JRE中的核心组成部分,承担分析和执行Java字节码的工作,而Java程序员通常并不需要深入了解JVM运行情况就可以开发出大型应...

weixin_30793643的博客 107
上一篇: Android屏幕适配解析
下一篇: 判断单链表是否存在环及寻找环的入口点
panfengsoftware
博客等级 码龄20年 38粉丝 34原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值