JVM学习笔记:第三章——运行时数据区(部分)
此章把运行时数据区当中较少的地方进行讲解后续讲解虚拟机栈、堆、方法区这些地方运行时数据区概述以及线程前言本章节主要讲述运行时数据区是类加载之后的阶段当我们通过前面的类的加载→链接验证→准备→解析→初始化这几个阶段完成之后就会用到执行引擎对我们的类进行使用同时执行引擎将会使用我们的运行时数据区类比一下大厨做饭我们把运行时数据区比作大厨后面的东西切好的菜品、厨具、调料等),而执行引擎就是烹饪的厨师。运行时数据区结构运行时数据区与内存内存是非常重要的系统资源是硬盘和CPU的中间仓库、桥梁承载着操作系统和应用程序的实时运行。JVM内存布局规定了Java在运行时内存申请、分配、管理的策略保障了JVM的高效稳定运行。不同的JVM对内存的划分方式和管理机制存在着部分差异。我们通过磁盘和网络IO得到的数据都需要先加载到内存当中然后CPU从内存当中获取数据进行读取JDK8运行时数据区示意图线程的内存空间Java虚拟机定义了若干种程序运行期间或使用到的运行时数据区其中一些随着虚拟机启动而创建随着虚拟机退出而销毁。另外一些则与线程一一对应这些与线程一一对应的数据区随着线程的开始和结束而创建和销毁。如下图灰色为单独线程私有的红色为多个线程共享的线程独有程序计数器、栈、本地方法栈线程共享堆、堆外内存永久代/元空间、代码缓存Runtime类每个JVM都只有一个Runtime实例。也就是运行时环境。线程JVM线程线程是一个程序当中的运行单元JVM允许一个应用当中有多个线程并行执行。在HotSpotJVM当中每个线程都和操作系统当中的本地线程直接映射。当一个Java线程准备好执行之后一个操作系统的本地线程也同时创建。Java线程执行终止之后本地线程也就回收。操作系统负责将线程安排调度到任何一个可用的CPU上。一旦本地线程初始化成功它就会调用Java线程的run方法。JVM系统线程在后台有许多线程运行。这些线程并不包括调用public static void main(String[] args)的main线程以及所有这个main线程创建的线程。这些主要的后台系统线程在HotSpot JVM当中主要是这几个虚拟机线程这种线程操作是需要JVM达到安全点才会出现。这种线程执行类型包括StopTheWorld的垃圾收集、线程栈收集、线程挂起、偏向锁撤销周期任务线程这种线程是时间周期事件的体现一般用于周期性操作的调度执行GC线程这种线程对在JVM当中不同种类的垃圾收集行为提供支持编译线程这种线程在运行的时候会将字节码编译成为本地代码信号调度线程这种线程接收到信号并发送给JVM在内部通过调用适当方法进行处理Stop The World 操作核心解释垃圾回收为例编程当中尤其是JVM、OG等运行时环境Stop-The-World特指为保证内存操作一致性暂时暂停应用程序中所有的用户线程业务逻辑线程以便垃圾回收器安全执行标记、清理等操作。“暂停”对象仅限当前进行线程内的应用线程用户代码而非整个程序的所有线程✅ 实际情况GC线程依旧在运行JVM当中GC线程继续工作仅用户代码暂停JVM安全点概述JVM语境下安全点指的是JVM可以安全的暂停所有Java线程执行全局性操作例如GC的特定程序位置它是HotSpot等主流虚拟机实现中的一种运行时协作机制本质目的是在不破坏程序语义的前提下完成需要“Stop-The-World”的操作。为什么需要安全点Java程序运行过程当中线程在不断执行字节码JIT会将热点代码编译成为机器码保存栈帧当中保存着对象引用寄存器当中也可能存储当发生GC时JVM需要遍历所有线程栈精确到所有对象引用Root标记存活的对象问题是如果线程在任意位置被强制暂停JVM可能无法确定某个寄存器当中是否有对象引用当前指令是否处于中间状态栈结构是否稳定所以我们需要等待线程运行到一个引用关系清晰栈状态稳定的位置停下来。这个位置就是安全点。本质从实现的角度讲安全点就是编译器在生成机器码时候插入的检查点HotSpot在以下位置插入 safepoint roll方法调用处循环回边while 、for等正常循环当中位置指向循环头部的“边”异常跳转点方法返回前当JVM需要STW时设置一个全局标识所有线程运行到最近的safe point检查该标识自行挂起这种机制被称为协作式中断什么时候触发安全点最常见触发场景就是GC其他场景偏向锁撤销类重新定义线程Dump……概念区分——安全点安全区安全点Safe Point必须运行到某个“特定位置”才能停线程是运行状态需要主动检查安全域Safe Region)适用于线程阻塞线程sleep线程wait当线程进入这些状态时它告诉JVM当前不改变对象引用可以安全使用GC这段时间叫安全域程序计数器PC寄存器介绍官方文档网址https://docs.oracle.com/javase/specs/jvms/se8/html/index.htmlJVM当中的程序计数寄存器Program Counter Register当中Register命名源于CPU寄存器寄存器存储指令相关的现场信息。CPU只有将数据装载到寄存器当中才能运行。这里并非是物理上的寄存器而是PC计数器/指令计数器或者称为程序钩子。实际上PC寄存器是对程序执行位置的抽象表示。PC寄存器使用了很小的内存空间几乎可以忽略不计。也是运行速度最快的存储区域JVM规范当中每个线程都有自己的程序计数器是线程私有的生命周期和线程的生命周期保持一致。任何时间一个线程都只有一个方法正在执行这就是所谓的当前方法。程序计数器或存储当前正在执行的Java方法的JVM指令地址如果正在执行native方法方法的实现并不在Java当中而是在本地语言通常是c/c当中实现则是undefined未定值因为此时PC并不指向有效的字节码地址PC程序计数器是程序控制流的指示器分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器完成。字节码解释器工作时通过计数器值的改变选取下一条需要执行的字节码指令。它是唯一一个在Java虚拟机规范中没有规定任何OutofMemoryError情况的区域。不存在出现内存不足的可能性作用PC寄存器用来存储指向下一条指令的地址也就是即将执行的代码。有执行引擎读取下一条指令并执行该指令。EXAMPLE查看字节码方法https://blog.csdn.net/21aspnet/article/details/88351875public class PCRegisterTest { public static void main(String[] args) { int i 10; int j 20; int k i j; String s abc; System.out.println(i); System.out.println(k); } }得到字节码Classfile /F:/IDEAWorkSpaceSourceCode/JVMDemo/out/production/chapter04/com/atguigu/java/PCRegisterTest.class Last modified 2020-11-2; size 675 bytes MD5 checksum 53b3ef104479ec9e9b7ce5319e5881d3 Compiled from PCRegisterTest.java public class com.atguigu.java.PCRegisterTest minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 Methodref #6.#26 // java/lang/Object.init:()V #2 String #27 // abc #3 Fieldref #28.#29 // java/lang/System.out:Ljava/io/PrintStream; #4 Methodref #30.#31 // java/io/PrintStream.println:(I)V #5 Class #32 // com/atguigu/java/PCRegisterTest #6 Class #33 // java/lang/Object #7 Utf8 init #8 Utf8 ()V #9 Utf8 Code #10 Utf8 LineNumberTable #11 Utf8 LocalVariableTable #12 Utf8 this #13 Utf8 Lcom/atguigu/java/PCRegisterTest; #14 Utf8 main #15 Utf8 ([Ljava/lang/String;)V #16 Utf8 args #17 Utf8 [Ljava/lang/String; #18 Utf8 i #19 Utf8 I #20 Utf8 j #21 Utf8 k #22 Utf8 s #23 Utf8 Ljava/lang/String; #24 Utf8 SourceFile #25 Utf8 PCRegisterTest.java #26 NameAndType #7:#8 // init:()V #27 Utf8 abc #28 Class #34 // java/lang/System #29 NameAndType #35:#36 // out:Ljava/io/PrintStream; #30 Class #37 // java/io/PrintStream #31 NameAndType #38:#39 // println:(I)V #32 Utf8 com/atguigu/java/PCRegisterTest #33 Utf8 java/lang/Object #34 Utf8 java/lang/System #35 Utf8 out #36 Utf8 Ljava/io/PrintStream; #37 Utf8 java/io/PrintStream #38 Utf8 println #39 Utf8 (I)V { public com.atguigu.java.PCRegisterTest(); descriptor: ()V flags: ACC_PUBLIC Code: stack1, locals1, args_size1 0: aload_0 1: invokespecial #1 // Method java/lang/Object.init:()V 4: return LineNumberTable: line 7: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/atguigu/java/PCRegisterTest; public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack2, locals5, args_size1 0: bipush 10 2: istore_1 3: bipush 20 5: istore_2 6: iload_1 7: iload_2 8: iadd 9: istore_3 10: ldc #2 // String abc 12: astore 4 14: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; 17: iload_1 18: invokevirtual #4 // Method java/io/PrintStream.println:(I)V 21: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; 24: iload_3 25: invokevirtual #4 // Method java/io/PrintStream.println:(I)V 28: return LineNumberTable: line 10: 0 line 11: 3 line 12: 6 line 14: 10 line 15: 14 line 16: 21 line 18: 28 LocalVariableTable: Start Length Slot Name Signature 0 29 0 args [Ljava/lang/String; 3 26 1 i I 6 23 2 j I 10 19 3 k I 14 15 4 s Ljava/lang/String; } SourceFile: PCRegisterTest.java左边数字代表的是指令地址指令偏移量也是PC寄存器当中可能存储的值然后执行引擎读取PC寄存器当中的值执行对应的指令。常见面试题使用PC寄存器存储字节码指令地址作用是什么/为什么使用PC寄存器记录当前线程的执行地址CPU需要不停切换各个线程切换回某个个线程的时候我们需要知道接着从哪里开始执行JVM字节码解释器需要通过PC寄存器的值明确下一条执行什么字节码指令为什么PC寄存器设定为私有的由于CPU使用时间片轮转机制在并发执行过程当中任何一个确定的时刻一个处理器内核只会运行一个线程的指令流加载变量、计算、判断、循环、写入内存等多条指令构成的流。这必然导致线程执行过程当中频繁的中断挂起与恢复唤醒即上下文切换为保障线程在被挂起之后下次能够从准确的位置恢复执行JVM在内存当中为每个线程分配了私有的PC计数器、虚拟机栈。PC计数器在各个线程之间互不干扰被线程私有。当CPU切换回该线程时依据PC计数器的值JVM知道下一步执行的代码从而保障程序流程分毫不差。CPU时间片CPU分配给每个线程时间每个线程被分配一个时间段称为时间片。宏观而言我们可以同步打开多个应用程序每个程序并行不悖同时运行微观而言一般情况下电脑上单核CPU/多核CPU核心数量都是有限的CPU的单个核心在任何一个特定纳秒级瞬间只能处理一个线程的指令流。为实现宏观上的并发操作系统引入时间片轮转机制将CPU执行时间分割为极短的时间片段通常为毫秒级别分配给不同的线程轮流执行。本地方法本地方法栈本地方法简单而言一个本地方法就是Java声明的、由非Java代码实现、通过JNIJava Native Interface和JVM交互执行的方法例如C/C实现。C当中也有类似机制例如可以使用extern告知C编译器调用C语言函数。定义一个本地方法native method时并不提供实现体因为其实现是非Java在外部实现的。作用融合不同的编程语言为Java所用EX注意标识符native可以和其他java标识符连用除abstractpublic class IHaveNatives { public native void Native1(int x); public native static long Native2(); private native synchronized float Native3(Object o); native void Native4(int[] ary) throws Exception; }使用的原因Java使用方便但是有些层次任务使用java实现并不容易或者对程序效率要求很高时就会存在一定问题。用于和Java环境外交互Java应用忧思需要和Java外的硬件进行交互本地方法存在的主要原因。例如Java的一些应用需要和操作系统、外部硬件交换信息。本地方法为Java提供了这样的机制提供一个非常简洁的接口无需了解Java应用之外的繁文缛节。与操作系统交互JVM支持着Java语言本身和运行时库它是Java程序赖以生存的平台它由一个解释器解释字节码和一些连接到本地代码的库组成。然而不管怎样它毕竟不是一个完整的系统它经常依赖于一底层系统的支持。这些底层系统常常是强大的操作系统。通过使用本地方法我们得以用Java实现了jre的与底层系统的交互甚至JVM的一些部分就是用C写的。还有如果我们要使用一些Java语言本身没有提供封装的操作系统的特性时我们也需要使用本地方法。Suns Java(Sun的Java平台实现)Sun的解释器使用的是c语言实现的使得其能够像C一样和外部进行交互。jre大部分使用的是Java实现的也可以通过本地方法和外界交互。EX类java.lang.Thread的setPriority()方法是用Java实现的但是它实现调用的是该类里的本地方法setPriority0()。这个本地方法是用C实现的并被植入JVM内部在Windows 95的平台上这个本地方法最终将调用Win32 SetThreadPriority() API。这是一个本地方法的具体实现由JVM直接提供JVM源码实现更多的情况是本地方法由外部的动态链接库external dynamic link library提供开发者通过C/C实现编译成为.dll/.so文件通过System.loadLibrary加载然后被JVM调用。本地方法现状使用的越来越少除非是与硬件有关的应用比如通过Java程序驱动打印机或者Java系统管理生产设备在企业级应用中已经比较少见。因为现在的异构领域间的通信很发达比如可以使用Socket通信也可以使用Web Service等等不多做介绍。本地方法栈Java虚拟机栈管理Java方法调用本地方法栈用于管理本地方法调用。注意本地方法栈也是线程私有的本地方法栈被允许实现成固定大小/可动态扩展的内存大小内存溢出方面和虚拟机栈表现相同StackOverflowError/OutOfMemoryError如果线程请求分配的栈容量超过本地方法栈允许的最大容量Java虚拟机将会抛出一个stackoverflowError 异常。如果本地方法栈可以动态扩展并且在尝试扩展的时候无法申请到足够的内存或者在创建新的线程时没有足够的内存去创建对应的本地方法栈那么Java虚拟机将会抛出一个outofMemoryError异常。具体做法本地方法栈当中登记本地方法执行引擎执行时加载本地方法。Attetion当某个线程调用一个本地方法时它就进入了一个全新的并且不再受虚拟机限制的世界。它和虚拟机拥有同样的权限。本地方法可以通过本地方法接口来访问虚拟机内部的运行时数据区它甚至可以直接使用本地处理器中的寄存器直接从本地内存的堆中分配任意数量的内存并不是所有的JVM都支持本地方法。因为Java虚拟机规范并没有明确要求本地方法栈的使用语言、具体实现方式、数据结构等。如果JVM产品不打算支持native方法也可以无需实现本地方法栈。在Hotspot JVM中直接将本地方法栈和虚拟机栈合二为一。

相关新闻

nodejs+Vue3+AI算力资源网上商城系统的设计与实现

nodejs+Vue3+AI算力资源网上商城系统的设计与实现

文章目录技术栈概述系统架构设计核心功能实现AI集成方案性能优化测试与部署扩展方向--nodejs技术栈--结论源码文档获取/同行可拿货,招校园代理 :文章底部获取博主联系方式!技术栈概述 Node.js:后端运行时环境,采用Express或NestJ…

2026/7/5 18:43:38 阅读更多 →
从Cyberhub到Aram Nagar:一个理性与创意兼具之人的内心漫游

从Cyberhub到Aram Nagar:一个理性与创意兼具之人的内心漫游

最近几周我思考良多。对于一些问题,即便没有明确的答案,我也似乎找到了一些方向。这些问题在我毫无防备时浮现,而在此之前,我甚至不知道自己曾有过这些疑问。或许,“顿悟”就是这样——在你最不经意的时候到来&#xf…

2026/7/5 19:51:52 阅读更多 →
题解:CF2195E

题解:CF2195E

题面 Idiot First Search 有一棵包含 n1n 1n1 个顶点的二叉树(nnn 为奇数),定点编号为 0,1,⋯,n0 , 1 , \cdots , n0,1,⋯,n。每个顶点最多可写入一个字母,初始时所有顶点均为空。树的根节点是顶点 000。 在这棵树中&#xff…

2026/7/4 14:51:22 阅读更多 →

最新新闻

Vue 实战:利用 IndexedDB 实现前端大文件断点续传

Vue 实战:利用 IndexedDB 实现前端大文件断点续传

、背景与痛点 前端下载大文件时&#xff0c;我们通常的做法是一行 fetch 拿到 response&#xff0c;转成 Blob&#xff0c;再丢给一个隐藏的 <a> 标签触发下载。这套逻辑在几十 KB 的图片、几百 KB 的 PDF 上完全没问题。可一旦文件跑到 100MB、1GB&#xff0c;问题就来…

2026/7/5 19:49:53 阅读更多 →
云平台 OCR(云端 API OCR)完整讲解

云平台 OCR(云端 API OCR)完整讲解

云平台 OCR(云端 API OCR)完整讲解 一、什么是云平台 OCR 各大云厂商(百度智能云、阿里云、腾讯云、华为云、谷歌云等)托管在云端服务器的 OCR 识别服务,开发者不用本地部署任何模型、推理库,仅通过 HTTP/HTTPS 网络接口上传图片,云端完成全部文字检测 + 识别,返回结…

2026/7/5 19:47:52 阅读更多 →
如何用Scan Tailor实现文档数字化的终极指南:让老旧扫描文档重获新生

如何用Scan Tailor实现文档数字化的终极指南:让老旧扫描文档重获新生

如何用Scan Tailor实现文档数字化的终极指南&#xff1a;让老旧扫描文档重获新生 【免费下载链接】scantailor 项目地址: https://gitcode.com/gh_mirrors/sc/scantailor 在数字化浪潮席卷全球的今天&#xff0c;你是否还在为堆积如山的老旧扫描文档而烦恼&#xff1f;…

2026/7/5 19:45:47 阅读更多 →
BLAST安全最佳实践:10个关键步骤保护你的AI浏览服务 [特殊字符]️

BLAST安全最佳实践:10个关键步骤保护你的AI浏览服务 [特殊字符]️

BLAST安全最佳实践&#xff1a;10个关键步骤保护你的AI浏览服务 &#x1f6e1;️ 【免费下载链接】blast Open-source VMs-as-a-service 项目地址: https://gitcode.com/gh_mirrors/blast14/blast 在当今AI技术快速发展的时代&#xff0c;BLAST作为开源的高性能Web浏览A…

2026/7/5 19:43:46 阅读更多 →
零基础AI换脸完全指南:roop-unleashed快速上手终极教程

零基础AI换脸完全指南:roop-unleashed快速上手终极教程

零基础AI换脸完全指南&#xff1a;roop-unleashed快速上手终极教程 【免费下载链接】roop-unleashed Evolved Fork of roop with Web Server and lots of additions 项目地址: https://gitcode.com/gh_mirrors/ro/roop-unleashed 想要体验电影级的AI换脸效果却担心技术门…

2026/7/5 19:41:46 阅读更多 →
免费压缩包密码恢复工具:3分钟找回遗忘密码的完整指南

免费压缩包密码恢复工具:3分钟找回遗忘密码的完整指南

免费压缩包密码恢复工具&#xff1a;3分钟找回遗忘密码的完整指南 【免费下载链接】ArchivePasswordTestTool 利用7zip测试压缩包的功能 对加密压缩包进行自动化测试密码 项目地址: https://gitcode.com/gh_mirrors/ar/ArchivePasswordTestTool 你是否曾经因为忘记ZIP、…

2026/7/5 19:41:46 阅读更多 →

日新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools&#xff1a;5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱&#xff0c;支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/5 0:03:34 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里&#xff0c;参与了关于混合后量子密码学的讨论&#xff0c;应付端点攻击找茬的人&#xff0c;还参与留言板讨论后&#xff0c;发现“威胁模型”对多数人仍是陌生概念&#xff0c;且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/5 0:03:34 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”&#xff1a;我理解的渗透测试到底是什么&#xff1f;每次看到新闻里说某个大公司的数据被“黑”了&#xff0c;或者某个网站被攻击导致服务瘫痪&#xff0c;你是不是和我一样&#xff0c;心里会冒出两个念头&#xff1a;一是“这黑客真厉害”&#x…

2026/7/5 0:07:38 阅读更多 →

周新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools&#xff1a;5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱&#xff0c;支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/5 0:03:34 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里&#xff0c;参与了关于混合后量子密码学的讨论&#xff0c;应付端点攻击找茬的人&#xff0c;还参与留言板讨论后&#xff0c;发现“威胁模型”对多数人仍是陌生概念&#xff0c;且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/5 0:03:34 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”&#xff1a;我理解的渗透测试到底是什么&#xff1f;每次看到新闻里说某个大公司的数据被“黑”了&#xff0c;或者某个网站被攻击导致服务瘫痪&#xff0c;你是不是和我一样&#xff0c;心里会冒出两个念头&#xff1a;一是“这黑客真厉害”&#x…

2026/7/5 0:07:38 阅读更多 →

月新闻