JVM内存模型深度解剖:分代策略、元空间与GC调优实战
堆
堆是Java虚拟机(JVM)内存管理的核心区域,其物理存储可能分散于不同内存页,但逻辑上被视为连续的线性空间。作为JVM启动时创建的第一个内存区域,堆承载着几乎所有的对象实例和数组对象(极少数通过逃逸分析优化至栈上分配的除外)。
内存细分
Java 7及之前版本
内存结构:新生代(Young Generation)、老年代(Old Generation)、永久代(PermGen)
Java 8及之后版本
内存结构:新生代(Young Generation)、老年代(Old Generation)、元空间(Metaspace)
新生代和老年代
一、堆内存基础参数
-
-Xms
示例:
设置堆内存初始分配大小。建议与-Xmx
保持一致,避免运行时堆容量动态调整带来的性能损耗。-Xms4g
表示初始分配4GB堆内存。 -
-Xmx
定义堆内存最大可扩展阈值。
二、堆内存代际划分
堆内存分为新生代(Young Generation)和老年代(Old Generation),采用分代回收策略优化性能:
- 新生代:存放短生命周期对象(约80%对象在此区域被回收)。
- 老年代:存放长期存活对象(部分对象生命周期与JVM进程一致)。
代际比例控制
- -XX:NewRatio
定义老年代与新生代的内存比例(默认值2:1)。例如,-XX:NewRatio=3
表示老年代占75%,新生代占25%。
调优建议:短生命周期对象多的应用可增大新生代比例,减少老年代GC压力。
三、新生代内部结构
新生代进一步细分为三个区域:
- Eden区
新创建对象默认分配至此区域。 - Survivor区(From/To)
存放Eden区GC后存活的对象,两个Survivor区交替使用。
Survivor区比例控制
- -XX:SurvivorRatio
定义Eden区与单个Survivor区的比例(默认8:1:1)。例如,Eden区占80%,每个Survivor区占10%。
四、新生代独立配置
- -Xmn
直接指定新生代内存大小(覆盖-XX:NewRatio
配置)。例如,-Xmn2g
强制新生代占2GB,老年代占剩余堆空间。
注意事项:需确保总堆内存(-Xmx
)足够容纳新生代与老年代之和。
对象分配过程
新创建的对象通常分配在Eden区。当Eden区空间不足时,会触发Minor GC(新生代垃圾回收),此时:
- 回收未被引用的对象(即垃圾对象)
- 将存活对象复制到Survivor From区(S0)
- 清空Eden区
当Eden区再次空间不足时:
- 触发第二次Minor GC
- 回收Eden区和Survivor From区(S0)的存活对象
- 将存活对象复制到Survivor To区(S1)
- 清空Eden区和Survivor From区(S0)
后续空间不足时的处理:
- 第三次Eden区不足时触发Minor GC
- 回收Eden区和Survivor To区(S1)的存活对象
- 将存活对象复制回Survivor From区(S0)
- 清空Eden区和Survivor To区(S1)
Survivor区的角色轮换:
- Survivor From和To区通过复制算法实现角色互换
- 空闲的Survivor区作为目标区(To区)
- 存活对象通过Eden区+当前From区→To区的方式转移
对象晋升机制:
- 每次Minor GC后,存活对象的年龄(经历GC次数)+1
- 当年龄达到-XX:MaxTenuringThreshold(默认15)时
- 对象晋升至老年代(Tenured Generation)
内存区域特性:
区域 | 回收频率 | 主要算法 | 典型问题 |
---|---|---|---|
新生代 | 高频 | 复制算法 | Eden区快速填满 |
老年代 | 低频 | 标记-清除/整理 | Full GC导致应用停顿 |
元空间 | 极低频 | 无(直接分配) | 类元数据溢出(OOM) |
对象内存分配遵循以下流程:
-
内存分配优先级
- 应用程序首先尝试在Eden区分配对象
- 若Eden区空间充足则直接完成分配
- 当Eden区空间不足时触发Minor GC
-
Young Generation回收机制
- 执行Minor GC时,存活对象会从Eden区和From Survivor区复制到To Survivor区
- 若对象年龄超过晋升阈值(默认15次),则直接晋升至老年代
- 若To Survivor区空间不足,存活对象将直接晋升至老年代
-
老年代分配策略
- 经过Minor GC后仍需分配的对象将尝试进入老年代
- 若老年代空间充足则完成分配
- 老年代空间不足时触发Major GC(Full GC)
-
容错机制
- Major GC执行后若仍无法满足内存需求,则抛出OutOfMemoryError
垃圾回收器分类与触发机制详解
一、垃圾回收器分类体系
部分回收器类型
(1) 新生代回收器(Minor GC)
- 回收范围:Eden区+S0/S1 Survivor区
- 典型场景:Eden区满时触发,采用复制算法
(2) 老年代回收器(Major GC)
- 回收范围:老年代完整空间
- 触发条件:晋升对象超过老年代剩余空间
(3) 混合回收器(Mixed GC)
- 回收范围:新生代+部分老年代
整堆回收器(Full GC)
- 回收范围:新生代+老年代+元空间
二、触发机制深度解析
垃圾回收器触发机制详解
一、新生代回收器(Minor GC)触发条件
-
核心触发条件
- 伊甸区空间耗尽:当Eden区100%被占满时强制触发
-
执行过程特性
- 采用复制算法:将存活对象从Eden+From区复制到To区
- 空间交换机制:复制完成后,Eden和From区清空,To区变为新的From区
- 强制STW:整个回收过程会暂停所有应用线程(Stop The World)
-
特殊场景
- 分配担保失败:若Survivor区无法容纳存活对象,且老年代剩余空间不足晋升总量时触发Full GC
二、老年代回收器(Major GC)触发条件
直接触发条件
- 老年代空间不足:对象从Survivor区晋升时发现老年代剩余空间不足
- 显式内存分配失败:大对象(如数组)直接申请老年代空间失败
三、Full GC触发条件
-
堆内存危机
- 老年代空间不足
- 元空间/方法区溢出
-
空间分配异常
- Eden转老年代失败:Minor GC时Survivor区无法容纳存活对象,且老年代剩余空间 < 待转移对象大小
- 跨代对象过大
-
主动触发机制
- System.gc()调用
为什么要对堆内存进行分代?不分代是否无法工作?
对堆内存进行分代的核心目的是优化垃圾回收(GC)性能。虽然理论上堆内存可以不分代运作,但分代策略通过生命周期差异化管理显著提升了效率。根据统计,70%-99%的对象属于临时对象(即"朝生夕死"),若每次GC都需要全堆扫描,将产生巨大的性能损耗。
实践验证
主流JVM(如HotSpot)均采用分代策略,其设计验证了理论优势:
- 98%的GC时间集中在新生代回收(Minor GC)
- 老年代GC频率可控制在每小时1次以内(取决于应用特性)
为对象分配内存:TLAB
为什么需要TLAB?
在多线程环境下,对象内存分配可能引发线程安全问题(如多个线程同时操作同一内存区域)。若通过全局加锁机制保证线程安全,会显著降低内存分配效率。TLAB(Thread-Local Allocation Buffer)通过为每个线程划分独立的内存区域,实现无锁化分配,减少线程竞争并提升吞吐量。
什么是TLAB?
TLAB是JVM针对堆内存(Eden区)设计的一种快速分配策略,其核心目标是优化多线程环境下的对象分配效率。
TLAB的工作机制
- 分配优先级:对象分配首选当前线程的TLAB空间。
- 空间管理:
- 默认占Eden区1%空间,通过
-XX:TLABWasteTargetPercent
调节目标占比。
- 默认占Eden区1%空间,通过
- 失败处理:TLAB分配失败时,需对Eden区加锁并进行GC或大对象分配。
JVM堆空间核心参数详解
-
-XX:+PrintFlagsInitial
打印所有JVM参数的初始默认值。 -
-XX:+PrintFlagsFinal
显示所有参数的最终生效值(包含通过命令行或配置文件修改后的值),。 -
-Xmx
设置堆空间最大内存(如-Xmx4g
)。建议与-Xms
设为相同值,避免堆内存动态扩展引发的性能波动。若物理内存充足,最大堆不超过系统可用内存的80%。 -
-Xmn
指定新生代固定大小(如-Xmn2g
)。官方推荐值为堆空间的1/3到1/2,过大会压缩老年代空间,增加Full GC频率;过小则导致频繁Minor GC。动态调整场景建议改用-XX:NewRatio
。 -
-XX:NewRatio
老年代与新生代比例(默认-XX:NewRatio=2
即1:2)。设置为4时,新生代占堆1/5,老年代4/5。与-Xmn
冲突时以-Xmn
优先。 -
-Xms
堆初始内存(如-Xms4g
)。生产环境建议等于-Xmx
,消除堆扩容引发的停顿。突发流量场景可预留扩容空间,如-Xms2g -Xmx4g
。 -
-XX:MaxTenuringThreshold
对象晋升老年代的年龄阈值(默认15)。若设为10,对象在Survivor区经历10次GC后进入老年代。调低可加速回收短期对象,但可能引发过早晋升;调高会增加Survivor区压力。 -
-XX:SurvivorRatio
控制Eden区与单个Survivor区的比例(默认-XX:SurvivorRatio=8
即Eden:S0:S1=8:1:1)。设置为4时,Eden:S0:S1=4:1:1。建议根据对象存活率调整,高存活率应用可增大Survivor。 -
-XX:HandlePromotionFailure
JDK 6 Update 24(小版本)后已废弃。原用于担保失败时强制Full GC。
逃逸分析与对象分配策略
一、对象分配的选择演进
传统认知中,Java对象均在堆内存分配。随着JIT编译器与逃逸分析技术成熟,栈上分配与标量替换打破了这一绝对性,使得对象分配策略呈现更精细化特征。
二、逃逸分析技术原理
-
核心机制
通过动态作用域分析判断对象生命周期:- 未逃逸对象:作用域严格限定在方法内部(未通过参数传递、返回值或成员变量暴露)
- 逃逸对象:发生方法逃逸(跨方法引用)或线程逃逸(多线程可见性)
-
技术优势
识别未逃逸对象后,可触发三级优化:- 栈上分配:对象随栈帧出栈自动销毁,规避堆内存分配与GC开销
- 同步消除:单线程访问对象时移除无必要的同步锁
- 标量替换:将聚合对象拆解为基本类型变量(标量),直接在栈/寄存器分配
三、优化策略实现细节
-
栈上分配条件
- 对象大小需适配栈容量(通常限制在几十KB)
- HotSpot实际通过标量替换模拟栈分配,未直接实现物理栈分配
-
同步锁消除案例
void method() {Object lock = new Object(); synchronized(lock) { // 锁对象未逃逸,同步块被JIT移除System.out.println(lock);} }
-
标量替换过程
原始代码:User user = new User(25); int age = user.age;
优化后等效:
int age = 25; // 直接使用基本类型
四、技术局限性
-
成熟度限制
逃逸分析自1999年论文提出至今仍存在局限:- 分析过程消耗CPU资源,可能抵消优化收益
- 极端场景下若无逃逸对象,分析成为冗余操作
-
堆分配主导地位
因HotSpot未完全实现物理栈分配,且字符串常量池(JDK7+)、TLAB机制仍依赖堆空间,当前对象分配仍以堆为主。
五、开发实践建议
-
作用域最小化
- 优先使用局部变量而非成员变量
- 避免通过返回值暴露内部对象(采用不可变拷贝)
-
参数配置建议
-XX:+DoEscapeAnalysis # 开启逃逸分析(默认启用) -XX:+EliminateAllocations # 启用标量替换
结论
逃逸分析为JVM提供了一种"条件式堆外分配"能力,但受技术成熟度与实现策略影响,现阶段「对象全量堆分配」的认知仍需作为基础原则。
方法区
Java运行时数据区结构解析
内存区域划分
Java虚拟机运行时数据区可分为线程私有与线程共享两大类别:
线程私有区域
- 虚拟机栈(Java Virtual Machine Stack)
存储方法调用的栈帧(局部变量表、操作数栈等),深度超过限制时抛出StackOverflowError
。 - 本地方法栈(Native Method Stack)
服务于Native方法调用,异常机制同虚拟机栈。 - 程序计数器(Program Counter Register)
记录当前线程执行的字节码指令地址,无内存溢出问题。
线程共享区域
- 堆(Heap)
存放对象实例,内存不足时抛出OutOfMemoryError
。 - 方法区(Method Area)
存储类结构信息(类型、字段、方法等),部分虚拟机实现可能在此区域抛出OutOfMemoryError
。
内存交互示例
以代码User user = new User();
为例:
- 方法区:加载
User.class
的类元数据(如字段描述、方法字节码等)。 - 虚拟机栈:声明
user
局部变量,存储指向堆对象的引用。 - 堆:分配
User
实例对象内存空间,内含指向方法区类元数据的指针。
方法区与堆的关系及特性
根据Java虚拟机规范定义,方法区在逻辑层面上属于堆的一部分,允许执行部分垃圾回收行为,但回收条件通常较为严格且触发频率较低。值得注意的是,在HotSpot虚拟机的具体实现中,方法区被独立划分为"非堆(Non-Heap)"内存空间,这使得它在物理存储层面与堆形成了明确的分隔。
核心特性解析:
-
内存共享机制
方法区与堆同属于线程共享的内存区域 -
物理空间特性
两者的物理内存分配均不要求绝对连续性 -
容量管理机制
当存储的对象元数据或类信息超过预设阈值时,方法区会遵循与堆相似的内存扩展策略:根据虚拟机配置选择是否自动扩容。当内存耗尽时将触发特定异常:
- JDK7及更早版本:抛出永久代(PermGen)内存溢出的OutOfMemoryError
- JDK8及后续版本:抛出元空间(Metaspace)内存溢出的OutOfMemoryError
设置方法区内存参数
-XX:MetaspaceSize | 设置元空间的初始内存阈值 |
-XX:MaxMetaspaceSize | 设置元空间的最大内存上限 |
平台依赖说明:
不同平台默认值存在差异,在Windows 64位环境下,默认初始值为21M(实际为20.8MB四舍五入),最大值为-1表示无限制(允许使用全部可用系统内存)。
GC触发机制:
当元空间内存使用达到MetaspaceSize设定值时,会触发Full GC进行元数据回收。该阈值被称为初始高水位线(High Water Mark)。
水位线动态调整规则:
- 若Full GC后回收空间不足,JVM会自动提升高水位线(不超过MaxMetaspaceSize)
- 若回收大量空间(如类加载器被卸载),高水位线会适当降低
与永久代的差异:
永久代(Java 8前)要求显式设置最大空间(-XX:MaxPermSize),而元空间采用更智能的自动扩容机制。建议生产环境始终设置MaxMetaspaceSize防止内存泄漏导致系统崩溃。
相关文章:
JVM内存模型深度解剖:分代策略、元空间与GC调优实战
堆 堆是Java虚拟机(JVM)内存管理的核心区域,其物理存储可能分散于不同内存页,但逻辑上被视为连续的线性空间。作为JVM启动时创建的第一个内存区域,堆承载着几乎所有的对象实例和数组对象(极少数通过逃逸分…...

STM32-TIM定时中断(6)
目录 一、TIM介绍 1、TIM简介 2、定时器类型 3、基本定时器 4、通用定时器 5、定时中断基本结构 6、时基单元的时序 (1)预分频器时序 (2)计数器时序 7、RCC时钟树 二、定时器输出比较功能(PWM) …...
微信小程序地图缩放scale隐性bug
bug1 在真机环境下通过this.mapCtx.getScale获取当前地图的缩放等级带小数, 当设置scale带小数时,地图会先执行到缩放到带小数的缩放等级,然后会再次缩放取整的缩放等级(具体向上取整还是向下取整未知,两种情况都观察…...
window 显示驱动开发-配置内存段类型
视频内存管理器(VidMm)和显示硬件仅支持某些类型的内存段。 因此,内核模式显示微型端口驱动程序(KMD)只能配置这些类型的段。 KMD 可以配置内存空间段和光圈空间段,其中不同: 内存空间段由保存…...

Modbus RTU 详解 + FreeMODBUS移植(附项目源码)
文章目录 前言一、Modbus RTU1.1 通信方式1.2 模式特点1.3 数据模型1.4 常用功能码说明1.5 异常响应码1.6 通信帧格式1.6.1 示例一:读取保持寄存器(功能码 0x03)1.6.2 示例二:写单个线圈(功能码 0x05)1.6.3…...

对称加密算法(AES、ChaCha20和SM4)Python实现——密码学基础(Python出现No module named “Crypto” 解决方案)
文章目录 一、对称加密算法基础1.1 对称加密算法的基本原理1.2 对称加密的主要工作模式 二、AES加密算法详解2.1 AES基本介绍2.2 AES加密过程2.3 Python中实现AES加密Python出现No module named “Crypto” 解决方案 2.4 AES的安全考量 三、ChaCha20加密算法3.1 ChaCha20基本介…...
JWT原理及工作流程详解
JSON Web Token(JWT)是一种开放标准(RFC 7519),用于在各方之间安全传输信息。其核心原理是通过结构化、签名或加密的JSON对象实现无状态身份验证和授权。以下是JWT的工作原理和关键组成部分: 1. JWT结构 J…...

【软件设计师:存储】16.计算机存储系统
一、主存储器 存储器是计算机系统中的记忆设备,用来存放程序和数据。 计算机中全部信息,包括输入的原始数据、计算机程序、中间运 行结果和最终运行结果都保存在存储器中。 存储器分为: 寄存器Cache(高速缓冲存储器)主存储器辅存储器一、存储器的存取方式 二、存储器的性…...
【Part 2安卓原生360°VR播放器开发实战】第三节|实现VR视频播放与时间轴同步控制
《VR 360全景视频开发》专栏 将带你深入探索从全景视频制作到Unity眼镜端应用开发的全流程技术。专栏内容涵盖安卓原生VR播放器开发、Unity VR视频渲染与手势交互、360全景视频制作与优化,以及高分辨率视频性能优化等实战技巧。 📝 希望通过这个专栏&am…...

WebRTC通信原理与流程
1、服务器与协议相关 1.1 STUN服务器 图1.1.1 STUN服务器在通信中的位置图 1.1.1 STUN服务简介 STUN(Session Traversal Utilities for NAT,NAT会话穿越应用程序)是一种网络协议,它允许位于NAT(或多重 NAT)…...

Java版ERP管理系统源码(springboot+VUE+Uniapp)
ERP系统是企业资源计划(Enterprise Resource Planning)系统的缩写,它是一种集成的软件解决方案,用于协调和管理企业内各种关键业务流程和功能,如财务、供应链、生产、人力资源等。它的目标是帮助企业实现资源的高效利用…...

Redis总结(六)redis持久化
本文将简单介绍redis持久化的两种方式 redis提供了两种不同级别的持久化方式: RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储.AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保…...
使用FastAPI微服务在AWS EKS中构建上下文增强型AI问答系统
系统概述 本文介绍如何使用FastAPI在AWS Elastic Kubernetes Service (EKS)上构建一个由多个微服务组成的AI问答系统。该系统能够接收用户输入的提示(prompt),通过调用其他微服务从AWS ElastiCache on Redis和Amazon DynamoDB获取相关上下文,然后利用AW…...

PMIC电源管理模块的PCB设计
目录 PMU模块简介 PMU的PCB设计 PMU模块简介 PMIC(电源管理集成电路)是现代电子设备的核心模块,负责高效协调多路电源的转换、分配与监控。它通过集成DC-DC降压/升压、LDO线性稳压、电池充电管理、功耗状态切换等功能,替代传统分…...
正大视角下的结构交易节奏:如何借助数据捕捉关键转折
正大视角下的结构交易节奏:如何借助数据捕捉关键转折 在日常的交易结构研究中,节奏与分型常常被误解为“预测工具”,实则更应作为状态识别的参考。正大团队在模型演化过程中提出了“节奏-结构对齐”的分析方式,通过数据驱动来判断…...

华为云Flexus+DeepSeek征文|DeepSeek-V3商用服务开通教程
目录 DeepSeek-V3/R1商用服务开通使用感受 DeepSeek-V3/R1商用服务开通 1、首先需要访问ModelArts Studio_MaaS_大模型即服务_华为云 2、在网站右上角登陆自己的华为云账号,如果没有华为云账号的话,则需要自己先注册一个。 3、接着点击ModelArts Stu…...
STM32F103RC中ADC1和ADC2通道复用
以下是STM32F103RC中ADC1和ADC2通道复用的示意图及文字说明,帮助直观理解这种共享关系: ADC1/ADC2引脚复用示意图 GPIO引脚 ADC1通道 ADC2通道 ┌─────────┐ ┌─────────┐ ┌─────────┐ │ PA0 ├─…...

Qt—鼠标移动事件的趣味小程序:会移动的按钮
1.项目目标 本次根据Qt的鼠标移动事件实现一个趣味小程序:当鼠标移动到按钮时,按钮就会随机出现在置,以至于根本点击不到按钮。 2.项目步骤 首先现在ui界面设计控件(也可以用代码的方式创建,就不多说了) 第一个按钮不需…...

鞋样设计软件
Sxy 64鞋样设计软件是一款专业级鞋类设计工具 专为鞋业设计师与制鞋企业开发 该软件提供全面的鞋样设计功能 包括二维开版 三维建模 放码排料等核心模块 支持从草图构思到成品输出的完整设计流程 内置丰富的鞋型数据库与部件库 可快速生成各种鞋款模板 软件采用智能放码技术 精…...

LeRobot 项目部署运行逻辑(六)——visualize_dataset_html.py/visualize_dataset.py
可视化脚本包括了两个方法:远程下载 huggingface 上的数据集和使用本地数据集 脚本主要使用两个: 目前来说,ACT 采集训练用的是统一时间长度的数据集,此外,这两个脚本最大的问题在于不能裁剪,这也是比较好…...

Windows Server 2025开启GPU分区(GPU-P)部署DoraCloud云桌面
本文描述在ShareStation工作站虚拟化方案的部署过程。 将服务器上部署 Windows Server、DoraCloud,并创建带有vGPU的虚拟桌面。 GPU分区技术介绍 GPU-P(GPU Partitioning) 是微软在 Windows 虚拟化平台(如 Hyper-V)中…...

TCP套接字通信核心要点
TCP套接字通信核心要点 通信模型架构 客户端-服务端模型 CS架构:客户端发起请求,服务端响应和处理请求双向通道:建立连接后实现全双工通信 服务端搭建流程 核心步骤 创建套接字 int server socket(AF_INET, SOCK_STREAM, 0); 参数说明&am…...

【C】初阶数据结构15 -- 计数排序与稳定性分析
本文主要讲解七大排序算法之外的另一种排序算法 -- 计数排序 目录 1 计数排序 1) 算法思想 2) 代码 3) 时间复杂度与空间复杂度分析 (1) 时间复杂度 (2) 空间复杂度 4) 计…...

高性能Python Web 框架--FastAPI 学习「基础 → 进阶 → 生产级」
以下是针对 FastAPI 的保姆级教程,包含核心概念、完整案例和关键注意事项,采用「基础 → 进阶 → 生产级」的三阶段教学法: 一、FastAPI介绍 FastAPI 是一个现代化的、高性能的 Python Web 框架,专门用于构建 APIs(应…...

Qt QML自定义LIstView
QML ListView组合拳做列表,代码不可直接复制使用,需要小改 先上图看效果 样式1 样式2 样式3 原理:操作:技术点:代码片段: 先上图看效果 样式1 三个表格组合成要给,上下滚动时,三个同时滚动&am…...

C++进阶--红黑树的实现
文章目录 红黑树的实现红黑树的概念红黑树的规则红黑树的效率 红黑树的实现红黑树的结构红黑树的插入变色单旋(变色)双旋(变色) 红黑树的查找红黑树的验证 总结:结语 很高兴和大家见面,给生活加点impetus&a…...

WPF之值转换器
文章目录 目录什么是值转换器IValueConverter接口Convert方法ConvertBack方法 创建和使用值转换器定义转换器类在XAML中使用转换器转换器参数(ConverterParameter) 常用转换器实现布尔值转可见性(BoolToVisibilityConverter)数值转…...
黄金、碳排放期货市场API接口文档
StockTV 提供了多种期货市场的数据接口,包括获取K线图表数据、查询特定期货的实时行情等。以下为对接期货市场的详细接口说明。 一、获取K线图表数据 通过调用/futures/kline接口,您可以获取指定期货合约的历史K线数据(例如开盘价、最高价、…...
云上系统CC攻击如何进行检测与防御?
云上系统遭受CC攻击(Challenge Collapsar,一种针对应用层的DDoS攻击)时,检测与防御需结合流量分析、行为识别和技术手段,以下是核心方法: 一、检测方法 异常流量分析 监控请求量突增&#…...

qml中的TextArea使用QSyntaxHighlighter显示高亮语法
效果图,左侧显示行号,右侧用TextArea显示文本内容,并且语法高亮。 2025年5月8号更新 1、多行文本注释 多行文本注释跟普通的高亮规则代码不太一样,代码需要修改,这里以JavaScript举例。 先制定多行文本注释规则&…...