Java虚拟机(JVM)的架构和工作原理,字节码执行流程
JVM的概念
JVM是Java Virtual Machine的缩写, 即Java虚拟机,也被称为Java程序运行的核心环境 。它是一种用于计算设备的规范,通过在实际的计算机上仿真模拟各种计算机功能来实现。JVM由一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个存储方法域等组成。它屏蔽了与操作系统平台相关的信息, 使得Java程序只需生成在JVM上运行的目标代码( 字节码) , 即可在多种平台上的JVM不加修改地运行。这是Java实现“一次编译, 到处运行”的关键。JVM在执行字节码时, 会将其解释成具体平台上的机器指令执行。
JVM的架构
JVM主要由以下几个部分组成:
类加载器
类加载器的概念
类加载器是JVM的一个重要组成部分,它实现了Java的动态加载特性。负责将Java类的字节码文件(.class文件)加载到位于内存的JVM中,并转换为运行时数据结构,为程序的执行做好准备。
类加载器的实质
类加载器负责实现类的加载过程,JVM是在内存中运行的。当Java程序被编译成字节码(.class文件)后,这些字节码不会直接在物理硬件上执行,而是被JVM加载到内存中,并由JVM的解释器或即时编译器(JIT Compiler)转换为对应平台的机器码后执行。这个过程实现了Java的“一次编写,到处运行”的特性,因为JVM为不同操作系统平台提供了统一的运行环境。
JVM的类加载机制
JVM的类加载机制是Java虚拟机(JVM)中一个非常核心且复杂的部分,它负责将类的字节码文件加载到内存中,并初始化为JVM可以直接使用的数据结构。下面我将详细说明JVM的类加载机制,主要分为几个关键阶段:加载、验证、准备、解析和初始化。
1. 加载(Loading)
加载阶段是类加载机制的第一个阶段。在这一阶段,JVM会查找并加载类的二进制数据,通常是类的.class文件。这些文件可以通过不同的途径被获取,如文件系统、网络、ZIP/JAR包等。加载完成后,JVM会在内存中生成一个代表这个类的java.lang.Class
对象,这个对象作为类数据的访问入口。
2. 验证(Verification)
验证阶段的主要目的是确保加载的类信息是符合JVM规范的,没有潜在的安全问题。验证过程包括文件格式验证、元数据验证、字节码验证和符号引用验证等步骤。通过这些验证,JVM可以确保类文件的正确性和安全性。
3. 准备(Preparation)
准备阶段主要为类的静态变量分配内存,并设置其初始值。这里的初始值是指数据类型的默认值,如int的默认值是0,boolean的默认值是false等。但需要注意的是,这里设置的只是默认值,而非用户代码中定义的初始值。用户定义的初始值将在初始化阶段被赋予。
4. 解析(Resolution)
解析阶段是将类、接口、字段和方法的符号引用转换为直接引用的过程。符号引用是一组符号,用于描述所引用的目标,而直接引用则是指向目标的指针、偏移量或句柄等。通过解析,JVM可以确定每个符号引用的具体指向,为后续的执行阶段做准备。
5. 初始化(Initialization)
初始化阶段是类加载机制的最后一个阶段。在这一阶段,JVM会执行类的构造器<clinit>()
方法,这个方法是由编译器自动生成的,用于初始化类的静态变量和执行静态代码块。需要注意的是,<clinit>()
方法只会被执行一次,且多个线程同时访问时,JVM会确保只有一个线程执行该方法。
6.类加载器(Class Loaders)
JVM中还存在类加载器的概念,它负责实现类的加载过程。Java中的类加载器采用了一种双亲委派模型(Parents Delegation Model),即当一个类加载器需要加载一个类时,它首先会请求其父类加载器进行加载,如果父类加载器无法加载,则再由当前类加载器进行加载。这种模型有助于保证Java平台的安全性,防止用户自定义的类替换掉Java核心类库中的类。
JVM类加载机制中的“双亲委派模型”
使用“双亲委派模型”的原因
在Java中,类加载器(Class Loader)负责将类的字节码文件加载到JVM中,并将其转换成JVM可以直接使用的数据结构。为了确保Java平台的安全性和类的唯一性,Java采用了一种名为“双亲委派模型”的类加载机制。
“双亲委派模型”的概念
双亲委派模型的核心思想是:当一个类加载器(称为子加载器)需要加载一个类时,它首先不会尝试自己去加载这个类,而是将这个加载请求委派给它的父加载器(如果有的话)去完成。每个类加载器都是如此,只有当父加载器无法加载这个类时,子加载器才会尝试自己去加载。
使用“双亲委派模型”的好处:
-
安全性:Java的核心类库(如
java.lang.*
、java.util.*
等)是由启动类加载器(Bootstrap ClassLoader)加载的,这些类在JVM启动时就被加载到内存中,并且无法被用户自定义的类加载器所替换。这样可以防止恶意代码通过自定义类加载器来替换核心类库中的类,从而破坏Java平台的安全性。 -
唯一性:由于类加载器之间的委托关系,Java中的每个类在JVM中都只会被加载一次,并且与它的类加载器相关联。这样就保证了类的唯一性,避免了因为类加载器的不同而导致相同全限定名的类被加载多次的问题。
-
沙箱安全机制:双亲委派模型还可以配合Java的沙箱安全机制(Sandbox Security Mechanism),为不同的应用程序提供隔离的运行环境,防止应用程序之间相互干扰。
注意:双亲委派模型并不是强制性的,用户可以通过自定义类加载器来打破这个模型,但这需要谨慎操作,以避免引入安全问题和类加载冲突。
“双亲委派模型”伪代码示例
假设我们有两个自定义的类加载器:ChildClassLoader
和 ParentClassLoader
,其中 ChildClassLoader
是 ParentClassLoader
的子类。我们将模拟类加载过程,并展示当 ChildClassLoader
尝试加载一个类时,它是如何首先委派给 ParentClassLoader
的。
// 假设的ParentClassLoader类
class ParentClassLoader extends ClassLoader {@Overridepublic Class<?> loadClass(String name) throws ClassNotFoundException {// 首先,检查该类是否已经被加载Class<?> clazz = findLoadedClass(name);if (clazz != null) {return clazz;}// 尝试从父类加载器(这里简化为系统类加载器)加载try {clazz = getParent().loadClass(name);return clazz;} catch (ClassNotFoundException e) {// 如果父类加载器加载不到,再尝试自己加载}// 这里应该添加自己加载类的逻辑,但为简化起见,我们直接抛出异常throw new ClassNotFoundException("Class " + name + " not found.");}
}// 假设的ChildClassLoader类
class ChildClassLoader extends ParentClassLoader {// 通常ChildClassLoader不需要重写loadClass方法,// 因为它已经继承了ParentClassLoader的loadClass实现,// 该实现已经遵循了双亲委派模型。// 但为了展示,我们可以保持这个类为空,或者添加一些特定的初始化逻辑。
}// 使用示例
public class ClassLoaderDemo {public static void main(String[] args) {// 创建ChildClassLoader实例ClassLoader childClassLoader = new ChildClassLoader();try {// 尝试加载一个类,比如java.lang.String// 注意:在实际应用中,不应该尝试加载Java核心库中的类,// 这里只是为了演示双亲委派模型。Class<?> clazz = childClassLoader.loadClass("java.lang.String");// 如果没有异常,说明类被成功加载了。// 但实际上,这个类是由启动类加载器(Bootstrap ClassLoader)加载的,// 而不是由我们的ChildClassLoader或ParentClassLoader。// 这里只是为了说明双亲委派的过程。System.out.println("Class loaded successfully: " + clazz.getName());} catch (ClassNotFoundException e) {System.out.println("Class not found: " + e.getMessage());}}
}// 注意:上面的示例代码并不完全准确,因为实际上java.lang.String是由启动类加载器加载的,
// 它不是通过自定义的类加载器链来加载的。但这里只是为了演示双亲委派的概念。
在这个例子中,ChildClassLoader
尝试加载 java.lang.String
类时,它会首先将其加载请求委派给它的父加载器 ParentClassLoader
,而 ParentClassLoader
又会进一步将其委派给它的父加载器(在这个简化的例子中,我们假设它直接委派给了系统类加载器,但在实际的JVM中,它最终会委派给启动类加载器)。由于 java.lang.String
是Java核心库中的类,因此它会被启动类加载器加载,而不是由我们的自定义类加载器加载。这个过程体现了双亲委派模型的工作原理。
运行时数据区:
程序计数器:
每个线程都有一个独立的程序计数器,用于指示当前线程正在执行的字节码指令的地址。
Java虚拟机栈:
每个线程在创建时都会创建一个虚拟机栈,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。
本地方法栈:
与虚拟机栈类似,但它是为执行本地方法(如C语言编写的方法)服务的。
Java堆:
JVM中内存最大的一块,被所有线程共享,用于存放对象实例和数组。
方法区:
在Java 8之前,方法区包含运行时常量池,用于存储类的结构信息、常量、静态变量等。Java 8之后,方法区被元空间(Metaspace)所替代,元空间使用本地内存而非JVM堆内存。
执行引擎:
负责执行字节码指令,包括解释执行和即时编译(JIT)两种方式。解释执行是指逐条解释字节码指令并执行,而JIT编译则是将部分字节码编译成机器码以提高执行效率。
垃圾回收器:
负责回收JVM中不再使用的对象,释放内存空间。垃圾回收器是JVM的一个重要组成部分,它采用多种算法来识别和回收垃圾对象。
JVM的工作原理
JVM的工作原理可以概括为以下几个步骤:
-
代码编译:Java源代码被编译成Java字节码,这是JVM能够识别的指令集。
-
类加载:JVM通过类加载器将字节码文件加载到内存中,并转换为运行时数据结构。
-
字节码验证:JVM对加载的字节码进行验证,确保它符合JVM规范,没有安全漏洞。
-
执行:JVM的执行引擎负责执行字节码指令。根据JVM的实现,可以选择解释执行或JIT编译执行。
-
内存管理:JVM负责管理Java程序执行过程中所使用的内存,包括堆、栈、方法区等。
-
垃圾回收:JVM的垃圾回收器定时回收不再使用的对象,释放内存空间。
常见JVM调优方法:
堆内存调优:
- 调整JVM的堆内存大小,包括初始堆大小(-Xms)和最大堆大小(-Xmx)。合理的堆内存设置可以避免因内存不足导致的性能问题,同时减少因内存过大造成的资源浪费。
- 通过设置新生代(Young Generation)和老年代(Old Generation)的大小,以及Eden区与 Survivor区的比例,优化垃圾回收(GC)的效率和内存利用率。
垃圾回收(GC)调优:
- 选择合适的垃圾回收器,如Serial GC、Parallel GC、CMS GC或G1 GC。不同的垃圾回收器适用于不同的应用场景,例如,G1 GC适用于需要低延迟和可预测停顿时间的应用。
- 调整垃圾回收器的相关参数,如新生代大小、老年代大小、GC线程数等,以优化垃圾回收的性能。
线程调优:
- 合理设置线程池的大小,避免创建过多的线程导致系统资源耗尽。
- 调整线程栈的大小,以适应应用程序的需求。线程栈过大可能导致内存浪费,过小则可能导致栈溢出错误。
JIT编译器调优:
- 通过调整JIT编译器的参数,如编译阈值、内联策略等,优化热点代码的执行效率。
- 合理使用JIT编译器的优化技术,如逃逸分析、标量替换等,提高代码的执行速度。
类加载调优:
- 优化类加载器的层次结构和加载策略,减少类加载的次数和提高加载速度。
- 使用自定义的类加载器来隔离不同的组件或库,避免类冲突和内存泄漏。
I/O调优:
- 使用合适的缓冲区大小和优化I/O操作方式(如NIO),减少I/O操作的次数和开销。
- 对于高并发I/O操作,考虑使用异步I/O或NIO的多路复用机制来提高性能。
监控和日志分析:
- 使用JVM监控工具(如JConsole、VisualVM、JProfiler等)对应用程序进行实时监控,分析内存使用、GC行为、线程状态等关键指标。
- 启用GC日志记录,并通过分析GC日志来识别性能瓶颈和优化点。
代码优化:
- 优化Java代码,减少不必要的对象创建和销毁,降低垃圾回收的压力。
- 使用合适的集合类型和算法,提高代码的执行效率。
- 避免在循环中创建大量对象或进行复杂的计算。
在Java代码中减少不必要的对象创建
重用对象:
- 当对象可以被多次使用时,考虑重用它们而不是每次都创建新的实例。例如,在循环中,可以将对象声明在循环外部,并在循环内部重复使用。
使用对象池:
- 对于创建成本较高的对象(如数据库连接、线程等),可以使用对象池来管理它们的生命周期。对象池可以减少对象的创建和销毁次数,从而提高性能。
避免在方法中创建不必要的对象:
- 在方法内部,尽量避免创建仅在方法内部使用的临时对象,特别是当这些对象可以在方法调用之间共享时。
使用字符串常量:
- 对于字符串常量,应该使用
String
的intern()
方法或直接在代码中使用字符串字面量,以便在JVM的字符串常量池中重用相同的字符串对象。利用基本数据类型:
- 当可以使用基本数据类型(如
int
、double
等)时,避免使用它们的包装类(如Integer
、Double
等),因为包装类的创建和拆箱操作会带来额外的性能开销。优化集合的使用:
- 在使用集合时,根据实际需求选择合适的集合类型,并合理设置集合的初始容量和加载因子,以减少扩容时的对象创建。
避免在循环中创建对象:
- 尽可能将循环中创建的对象移到循环外部,如果对象必须在循环中创建,考虑是否可以使用同一个对象并更新其状态。
使用不可变对象:
- 不可变对象一旦被创建,其状态就不能被改变,因此它们可以被安全地共享而无需担心数据一致性问题。使用不可变对象可以减少对象的创建和复制次数。
利用缓存:
- 对于计算结果或对象,如果它们可以被缓存并在后续请求中重用,那么使用缓存可以显著减少对象的创建和计算开销。
分析并优化热点代码:
- 使用性能分析工具(如JProfiler、VisualVM等)来识别性能瓶颈和热点代码。针对这些热点代码进行优化,减少不必要的对象创建和内存分配。
字节码执行流程
加载类文件
- 类装载器:负责将Java类文件(.class文件)加载到JVM中。在这个过程中,类装载器会验证类文件是否符合Java类文件格式规范。
- 加载到JVM:类文件被加载后,JVM会为其创建一个Class对象,并存储在方法区(或元空间,从JDK 8开始)中。
字节码校验
- 字节码校验器:对加载的类文件中的字节码进行校验,确保代码中不包含非法操作,如访问违规内存、执行不安全的系统调用等。这是JVM实现安全性的重要环节。
解释执行
- 解释器:如果字节码通过了校验,JVM的解释器会逐条解释执行字节码指令。解释器会将字节码转换为机器码,然后交由底层操作系统执行。
- 即时编译器:为了提高执行效率,JVM还包含了一个即时编译器。JIT编译器会在运行时将热点代码(即频繁执行的代码)编译成机器码,以提高执行速度。
运行时数据区
在执行过程中,JVM会利用运行时数据区来存储和管理程序运行时的数据,即在执行过程中,JVM的内存管理器负责分配和回收内存。
垃圾回收
当对象不再被引用时,JVM的垃圾回收器会回收其占用的内存空间。
程序结束
当Java程序执行完毕或遇到异常终止时,JVM会卸载已加载的类并释放所有资源。
相关文章:
Java虚拟机(JVM)的架构和工作原理,字节码执行流程
JVM的概念 JVM是Java Virtual Machine的缩写, 即Java虚拟机,也被称为Java程序运行的核心环境 。它是一种用于计算设备的规范,通过在实际的计算机上仿真模拟各种计算机功能来实现。JVM由一套字节码指令集、一组寄存器、一个栈、一个…...
416.分割等和子集
416.分割等和子集 给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。 示例 1: 输入:nums [1,5,11,5] 输出:true 解释:数组可以分割成 [1, 5, 5] 和…...
python初始化一个三维数组
文章目录 1.什么是三维数组2.那我应该如何初始化一个自定义长度的三维数组呢? 1.什么是三维数组 从最外层开始理解,可以理解为一维数组,里面套了一个二维数组(12等于三维数组) arr [ [[], []], [[], [], []], [[],[]]…...
EI会议推荐-第二届大数据与数据挖掘国际会议(BDDM 2024)
第二届大数据与数据挖掘国际会议(BDDM 2024) 1、基本信息 大会官网:http://www.icbddm.org/ 官方邮箱:icbddm163.com 主办方:武汉纺织大学 会议时间:2024年12月13日-12月15日 会议地点:湖…...
RK3566/RK3568 Android 11 动态显示/隐藏下拉框
概述 在系统服务中增加显示/隐藏状态栏方法,在上层app动态调用显示/隐藏下拉框方法,设备关机和重启后也能继续生效。 创建全局变量 1.定义全局变量 在frameworks/base/core/java/android/provider/Settings.java中添加 /*** Disable drop-down box* @hide*/public static…...

Android图片缓存工具类LruCache原理和使用介绍
LruCache & DiskLruCache原理。 常用的三级缓存主要有LruCache、DiskLruCache、网络,其中LruCache对应内存缓存、 DiskLruCache对应持久化缓存。Lru表示最近最少使用,意思是当缓存到达限制时候,优先淘汰近 期内最少使用的缓存,…...
生活杂记1
生命中,总有一些事需要你一生去治愈,我把这些杂记写出来,写完了就不再想了,太内耗了…hahaha~ 因为嘴馋,小时候经常去老姑家,她家有各类零食及平时很少吃的“山珍海味”。去的次数多了,就和她家…...
go常用代码
连接阿波罗: 默认properties类型 package mainimport ("fmt""github.com/apolloconfig/agollo/v4""github.com/apolloconfig/agollo/v4/env/config" )func main() {c : &config.AppConfig{AppID: "2222",Cl…...
各种各样的正则表达式
一、校验数字的表达式 数字:^[0-9]*$ n位的数字:^\d{n}$ 至少n位的数字:^\d{n,}$ m-n位的数字:^\d{m,n}$ 零和非零开头的数字:^(0|[1-9][0-9]*)$ 非零开头的最多带两位小数的数字:^([1-9][0-9]*)+(.[0-9]{1,2})?$ 带1-2位小数的正数或负数:^(\-)?\d+(\.\d{1,2})?$ 正…...
WebRTC 基础
WebRTC 基础 目录 什么是 WebRTCWebRTC 的基本概念WebRTC 的基本流程 连接建立流程图 WebRTC 的基本对象 RTCPeerConnectionRTCSessionDescriptionRTCIceCandidate WebRTC API 详解 RTCPeerConnection API媒体流 API 详细的代码示例 基本连接示例完整的 WebRTC 实现示例 总结…...

半天攻略:用ChatGPT快速搞定高质量论文,从选题到完稿一站式指南!
在学术论文的撰写过程中,ChatGPT可以作为一个强大的辅助工具,帮助完成从确定主题到整理参考文献的各个环节。接下来,我们将详细介绍如何利用ChatGPT提升论文写作的效率和质量。 确定论文主题 初步探索:通过ChatGPT探索主题&#…...

探索PDF的奥秘:pdfrw库的神奇之旅
文章目录 探索PDF的奥秘:pdfrw库的神奇之旅背景:为何选择pdfrw?pdfrw是什么?如何安装pdfrw?五个简单的库函数使用方法场景应用:pdfrw在实际工作中的应用常见问题与解决方案总结 探索PDF的奥秘:p…...

修改jupyter notebook 默认浏览器(不动配置文件,改系统默认浏览器)
最开始把联想浏览器切到EDGE就是用的修改系统的默认浏览器。不知怎么的现在搜到的方法都是在说修改配置文件😓。 不想动配置文件,平时对默认浏览器没有特殊要求的,可以用这个方法。 这里是把默认浏览器改成联想浏览器,电脑也是联…...

一个基于共享内存的内存数据库:1 介绍
初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的,可以在任何平台上使用。 源码指引:github源…...
可视化编程 制作在线点名程序,人工和随机生成两种模式
以下是对这段代码的分析: 一、功能概述 这是一个使用 Python 的 Tkinter 库创建的图形用户界面(GUI)应用程序,主要功能是进行在线点名和随机抽奖。可以模拟在一个有六排六列座位布局的场景中进行点名操作和不同规模的随机抽奖。 二、主要函数和变量 窗口设置和变量初始化:…...
pdb在CDB间搬迁 dblink 与rman
create pluggable database <pdb_name> from <pdb_name><dblink> relocate availability max create_file_destxxxxx;-----改变目录 How to relocate a PDB from one CDB to another with minimal down time -12.2 Release (Doc ID 2396518.1) GOAL How to …...
Linux系统中的fork与vfork的区别
目录 一、引言 二、fork与vfork的基本概念 1.fork() 2.vfork() 三、fork与vfork的区别 1.内存分配策略 2.执行顺序 3.性能 4.安全性 四、总结 本文将详细介绍Linux系统中fork与vfork这两个系统调用的区别,帮助读者更好地理解它们在实际编程中的应用。 一、引言…...

特殊类的设计和类型转换
文章目录 特殊类1.请设计一个类,不能被拷贝2. 请设计一个类,只能在堆上创建对象3. 请设计一个类,只能在栈上创建对象 (★)4. 请设计一个类,不能被继承5. 请设计一个类,只能创建一个对象(单例模式…...
ES模块导入、导出学习笔记
ES模块导入、导出学习笔记 1、命名导出、导入1.1、声明时直接导出1.2、先声明,再导出 2、默认导出2.1、声明时直接导出2.2、先声明,再导出 3、命名导出 VS 默认导出3.1、命名导出3.2、默认导出3.3、同时使用 4、使用 as 关键字4.1、在 import 中使用 as4…...

Bagging: 数量,而不是质量。
由 AI 生成:过度简化的树、引导聚合、集成方法、弱学习器、减少方差 集成方法 — 数量,而不是质量 一、说明 机器学习中的集成方法是指组合多个模型以提高预测性能的技术。集成方法背后的基本思想是聚合多个基础模型(通常称为弱学习器&#…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...
Go语言多线程问题
打印零与奇偶数(leetcode 1116) 方法1:使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...

TSN交换机正在重构工业网络,PROFINET和EtherCAT会被取代吗?
在工业自动化持续演进的今天,通信网络的角色正变得愈发关键。 2025年6月6日,为期三天的华南国际工业博览会在深圳国际会展中心(宝安)圆满落幕。作为国内工业通信领域的技术型企业,光路科技(Fiberroad&…...

密码学基础——SM4算法
博客主页:christine-rr-CSDN博客 专栏主页:密码学 📌 【今日更新】📌 对称密码算法——SM4 目录 一、国密SM系列算法概述 二、SM4算法 2.1算法背景 2.2算法特点 2.3 基本部件 2.3.1 S盒 2.3.2 非线性变换 编辑…...

【免费数据】2005-2019年我国272个地级市的旅游竞争力多指标数据(33个指标)
旅游业是一个城市的重要产业构成。旅游竞争力是一个城市竞争力的重要构成部分。一个城市的旅游竞争力反映了其在旅游市场竞争中的比较优势。 今日我们分享的是2005-2019年我国272个地级市的旅游竞争力多指标数据!该数据集源自2025年4月发表于《地理学报》的论文成果…...
32位寻址与64位寻址
32位寻址与64位寻址 32位寻址是什么? 32位寻址是指计算机的CPU、内存或总线系统使用32位二进制数来标识和访问内存中的存储单元(地址),其核心含义与能力如下: 1. 核心定义 地址位宽:CPU或内存控制器用32位…...

基于stm32F10x 系列微控制器的智能电子琴(附完整项目源码、详细接线及讲解视频)
注:文章末尾网盘链接中自取成品使用演示视频、项目源码、项目文档 所用硬件:STM32F103C8T6、无源蜂鸣器、44矩阵键盘、flash存储模块、OLED显示屏、RGB三色灯、面包板、杜邦线、usb转ttl串口 stm32f103c8t6 面包板 …...

【PX4飞控】mavros gps相关话题分析,经纬度海拔获取方法,卫星数锁定状态获取方法
使用 ROS1-Noetic 和 mavros v1.20.1, 携带经纬度海拔的话题主要有三个: /mavros/global_position/raw/fix/mavros/gpsstatus/gps1/raw/mavros/global_position/global 查看 mavros 源码,来分析他们的发布过程。发现前两个话题都对应了同一…...