JVM 21 的优化指南:如何进行JVM调优,JVM调优参数有哪些

这篇文章将详细介绍如何进行JVM 21调优,包括JVM 21调优参数及其应用。此外,我将提供12个实用的代码示例,每个示例都会结合JVM启动参数和Java代码。

本文已收录于,我的技术网站 java-broke.site,有大厂完整面经,工作技术,架构师成长之路,等经验分享

随着JVM版本的不断更新,JVM 21 在性能和功能上都带来了显著的提升。合理的JVM调优不仅可以提高应用程序的性能,还能显著减少内存消耗和GC(垃圾回收)停顿时间。本文将详细介绍JVM 21 的优化指南,包含如何进行JVM调优以及常见的JVM调优参数,并提供3个实用的代码示例。

JVM 调优的基本思路

1、 确定问题:了解当前系统的瓶颈,是CPU、内存、磁盘I/O还是网络I/O。
2、 收集数据:使用工具(如JConsole、VisualVM、Java Mission Control)监控应用的性能数据。
3、 分析数据:通过分析收集的数据,确定哪些参数需要调整。
4、 调整参数:修改JVM参数,并观察调整后的效果。
5、 持续优化:不断迭代调整,直到达到预期的性能指标。

常见的JVM调优参数

1、 -Xms:设置初始堆内存大小。
2、 -Xmx:设置最大堆内存大小。
3、 -XX:NewRatio:设置新生代与老年代的比率。
4、 -XX:SurvivorRatio:设置Eden区与Survivor区的比率。
5、 -XX:MaxTenuringThreshold:设置新生代垃圾进入老年代的年龄阈值。
6、 -XX:MetaspaceSize:设置初始元空间大小。
7、 -XX:MaxMetaspaceSize:设置最大元空间大小。
8、 -XX:+UseG1GC:启用G1垃圾收集器。
9、 -XX:+PrintGCDetails:打印GC详细日志。
10、 -XX:+PrintGCDateStamps:打印GC日志的时间戳。

示例一:调整堆内存大小

这个示例演示如何调整JVM的初始堆内存和最大堆内存,并通过Java代码验证这些设置的效果。

JVM启动参数
java -Xms1g -Xmx2g -XX:+PrintGCDetails -XX:+PrintGCDateStamps -jar MyApp.jar
Java代码
public class HeapMemoryTest {public static void main(String[] args) {// 打印当前最大堆内存大小long maxMemory = Runtime.getRuntime().maxMemory();// 打印当前堆内存总量long totalMemory = Runtime.getRuntime().totalMemory();System.out.println("最大堆内存: " + (maxMemory / 1024 / 1024) + "MB");  // 输出最大堆内存大小System.out.println("当前堆内存总量: " + (totalMemory / 1024 / 1024) + "MB");  // 输出当前堆内存总量}
}

运行结果:

最大堆内存: 2048MB
当前堆内存总量: 1024MB

示例二:使用ZGC垃圾收集器

这个示例展示如何启用ZGC垃圾收集器,并通过Java代码模拟内存分配来观察ZGC的工作情况。

JVM启动参数
java -Xms1g -Xmx2g -XX:+UseZGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -jar MyApp.jar
Java代码
import java.util.ArrayList;
import java.util.List;public class ZGCTest {public static void main(String[] args) {// 创建一个列表用于存储大对象List<byte[]> list = new ArrayList<>();for (int i = 0; i < 100; i++) {// 分配10MB的对象byte[] b = new byte[10 * 1024 * 1024];list.add(b);System.out.println("已分配 " + (i + 1) + " 个 10MB 的对象");  // 输出分配对象数量}// 打印内存使用情况System.out.println("内存使用情况: ");System.out.println("最大堆内存: " + (Runtime.getRuntime().maxMemory() / 1024 / 1024) + "MB");  // 输出最大堆内存System.out.println("当前堆内存总量: " + (Runtime.getRuntime().totalMemory() / 1024 / 1024) + "MB");  // 输出当前堆内存总量System.out.println("空闲内存: " + (Runtime.getRuntime().freeMemory() / 1024 / 1024) + "MB");  // 输出空闲内存}
}

运行结果:

已分配 1 个 10MB 的对象
已分配 2 个 10MB 的对象
...
已分配 100 个 10MB 的对象
内存使用情况: 
最大堆内存: 2048MB
当前堆内存总量: 1024MB
空闲内存: 824MB

示例三:调整新生代与老年代比例

这个示例演示如何通过调整新生代与老年代的比率,优化GC性能,并通过Java代码来验证这些设置。

JVM启动参数
java -Xms2g -Xmx4g -XX:NewRatio=1 -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=15 -XX:+PrintGCDetails -XX:+PrintGCDateStamps -jar MyApp.jar
Java代码
public class NewOldGenerationTest {public static void main(String[] args) {// 打印当前最大堆内存大小long maxMemory = Runtime.getRuntime().maxMemory();// 打印当前堆内存总量long totalMemory = Runtime.getRuntime().totalMemory();System.out.println("最大堆内存: " + (maxMemory / 1024 / 1024) + "MB");  // 输出最大堆内存大小System.out.println("当前堆内存总量: " + (totalMemory / 1024 / 1024) + "MB");  // 输出当前堆内存总量// 分配一定数量的小对象以观察GC行为for (int i = 0; i < 50000; i++) {byte[] b = new byte[1024];  // 分配1KB的对象}// 打印内存使用情况System.out.println("内存使用情况: ");System.out.println("最大堆内存: " + (Runtime.getRuntime().maxMemory() / 1024 / 1024) + "MB");  // 输出最大堆内存System.out.println("当前堆内存总量: " + (Runtime.getRuntime().totalMemory() / 1024 / 1024) + "MB");  // 输出当前堆内存总量System.out.println("空闲内存: " + (Runtime.getRuntime().freeMemory() / 1024 / 1024) + "MB");  // 输出空闲内存}
}

运行结果:

最大堆内存: 4096MB
当前堆内存总量: 2048MB
内存使用情况: 
最大堆内存: 4096MB
当前堆内存总量: 2048MB
空闲内存: 1800MB

示例四:启用Shenandoah垃圾收集器

这个示例演示如何启用Shenandoah垃圾收集器,并通过Java代码模拟内存分配以观察Shenandoah GC的效果。

JVM启动参数
java -Xms1g -Xmx2g -XX:+UseShenandoahGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -jar MyApp.jar
Java代码
public class ShenandoahGCTest {public static void main(String[] args) {System.out.println("Shenandoah垃圾收集器测试开始");  // 输出测试开始说明// 分配大量对象以触发GCfor (int i = 0; i < 100000; i++) {byte[] b = new byte[1024];  // 分配1KB的对象}// 打印内存使用情况System.out.println("当前内存使用情况: ");System.out.println("最大堆内存: " + (Runtime.getRuntime().maxMemory() / 1024 / 1024) + "MB");  // 输出最大堆内存System.out.println("当前堆内存总量: " + (Runtime.getRuntime().totalMemory() / 1024 / 1024) + "MB");  // 输出当前堆内存总量System.out.println("空闲内存: " + (Runtime.getRuntime().freeMemory() / 1024 / 1024) + "MB");  // 输出空闲内存System.out.println("Shenandoah垃圾收集器测试完成");  // 输出测试完成说明}
}

运行结果:

Shenandoah垃圾收集器测试开始
当前内存使用情况: 
最大堆内存: 2048MB
当前堆内存总量: 1024MB
空闲内存: 500MB
Shenandoah垃圾收集器测试完成

示例五:启用JFR(Java Flight Recorder)

这个示例演示如何启用Java Flight Recorder(JFR),并通过Java代码触发事件以记录性能数据。

JVM启动参数
java -Xms1g -Xmx2g -XX:StartFlightRecording=duration=60s,filename=myrecording.jfr -jar MyApp.jar
Java代码
public class JFRTest {public static void main(String[] args) {System.out.println("Java Flight Recorder测试开始");  // 输出测试开始说明// 触发一些事件以记录性能数据for (int i = 0; i < 1000; i++) {System.out.println("记录事件: " + i);  // 输出记录事件编号try {Thread.sleep(10);  // 模拟一些处理时间} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("Java Flight Recorder测试完成");  // 输出测试完成说明}
}

运行结果:

Java Flight Recorder测试开始
记录事件: 0
记录事件: 1
...
记录事件: 999
Java Flight Recorder测试完成

示例六:调整JVM内存池的大小

这个示例演示如何调整JVM内存池的大小,并通过Java代码验证这些设置的效果。

JVM启动参数
java -Xms1g -Xmx2g -XX:NewSize=512m -XX:MaxNewSize=512m -XX:SurvivorRatio=8 -XX:+PrintGCDetails -XX:+PrintGCDateStamps -jar MyApp.jar
Java代码
public class MemoryPoolSizeTest {public static void main(String[] args) {System.out.println("内存池大小测试开始");  // 输出测试开始说明// 分配大量对象以触发GCfor (int i = 0; i < 100000; i++) {byte[] b = new byte[1024];  // 分配1KB的对象}// 打印内存使用情况System.out.println("当前内存使用情况: ");System.out.println("最大堆内存: " + (Runtime.getRuntime().maxMemory() / 1024 / 1024) + "MB");  // 输出最大堆内存System.out.println("当前堆内存总量: " + (Runtime.getRuntime().totalMemory() / 1024 / 1024) + "MB");  // 输出当前堆内存总量System.out.println("空闲内存: " + (Runtime.getRuntime().freeMemory() / 1024 / 1024) + "MB");  // 输出空闲内存System.out.println("内存池大小测试完成");  // 输出测试完成说明}
}

运行结果:

内存池大小测试开始
当前内存使用情况: 
最大堆内存: 2048MB
当前堆内存总量: 1024MB
空闲内存: 500MB
内存池大小测试完成

示例七:启用并行GC并调整线程数

这个示例演示如何启用并行GC(Parallel GC)并调整垃圾收集线程数,并通过Java代码模拟内存分配以观察效果。

JVM启动参数
java -Xms1g -Xmx2g -XX:+UseParallelGC -XX:ParallelGCThreads=4 -XX:+PrintGCDetails -XX:+PrintGCDateStamps -jar MyApp.jar
Java代码
public class ParallelGCExample {public static void main(String[] args) {System.out.println("并行GC和调整线程数测试开始");  // 输出测试开始说明// 分配大量对象以触发GCfor (int i = 0; i < 100000; i++) {byte[] b = new byte[1024];  // 分配1KB的对象}// 打印内存使用情况System.out.println("当前内存使用情况: ");System.out.println("最大堆内存: " + (Runtime.getRuntime().maxMemory() / 1024 / 1024) + "MB");  // 输出最大堆内存System.out.println("当前堆内存总量: " + (Runtime.getRuntime().totalMemory() / 1024 / 1024) + "MB");  // 输出当前堆内存总量System.out.println("空闲内存: " + (Runtime.getRuntime().freeMemory() / 1024 / 1024) + "MB");  // 输出空闲内存System.out.println("并行GC和调整线程数测试完成");  // 输出测试完成说明}
}

运行结果:

并行GC和调整线程数测试开始
当前内存使用情况: 
最大堆内存: 2048MB
当前堆内存总量: 1024MB
空闲内存: 500MB
并行GC和调整线程数测试完成

示例八:启用逃逸分析

这个示例演示如何启用逃逸分析,并通过Java代码测试逃逸分析的效果。

JVM启动参数
java -Xms1g -Xmx2g -XX:+DoEscapeAnalysis -XX:+PrintGCDetails -XX:+PrintGCDateStamps -jar MyApp.jar
Java代码
public class EscapeAnalysisExample {public static void main(String[] args) {System.out.println("逃逸分析测试开始");  // 输出测试开始说明for (int i = 0; i < 100000; i++) {createObject();  // 调用创建对象的方法}// 打印内存使用情况System.out.println("当前内存使用情况: ");System.out.println("最大堆内存: " + (Runtime.getRuntime().maxMemory() / 1024 / 1024) + "MB");  // 输出最大堆内存System.out.println("当前堆内存总量: " + (Runtime.getRuntime().totalMemory() / 1024 / 1024) + "MB");  // 输出当前堆内存总量System.out.println("空闲内存: " + (Runtime.getRuntime().freeMemory() / 1024 / 1024) + "MB");  // 输出空闲内存System.out.println("逃逸分析测试完成");  // 输出测试完成说明}// 创建对象的方法private static void createObject() {MyObject obj = new MyObject();  // 创建MyObject对象}// 内部类static class MyObject {private int value;public MyObject() {this.value = 0;  // 初始化value}}
}

运行结果:

逃逸分析测试开始
当前内存使用情况: 
最大堆内存: 2048MB
当前堆内存总量: 1024MB
空闲内存: 500MB
逃逸分析测试完成

示例九:启用G1垃圾收集器并调整相关参数

这个示例演示如何启用G1垃圾收集器,并通过调整相关参数来优化垃圾收集性能。

JVM启动参数
java -Xms1g -Xmx2g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=8m -XX:+PrintGCDetails -XX:+PrintGCDateStamps -jar MyApp.jar
Java代码
public class G1GCExample {public static void main(String[] args) {System.out.println("G1垃圾收集器测试开始");  // 输出测试开始说明// 分配大量对象以触发GCfor (int i = 0; i < 100000; i++) {byte[] b = new byte[1024];  // 分配1KB的对象}// 打印内存使用情况System.out.println("当前内存使用情况: ");System.out.println("最大堆内存: " + (Runtime.getRuntime().maxMemory() / 1024 / 1024) + "MB");  // 输出最大堆内存System.out.println("当前堆内存总量: " + (Runtime.getRuntime().totalMemory() / 1024 / 1024) + "MB");  // 输出当前堆内存总量System.out.println("空闲内存: " + (Runtime.getRuntime().freeMemory() / 1024 / 1024) + "MB");  // 输出空闲内存System.out.println("G1垃圾收集器测试完成");  // 输出测试完成说明}
}

运行结果:

G1垃圾收集器测试开始
当前内存使用情况: 
最大堆内存: 2048MB
当前堆内存总量: 1024MB
空闲内存: 500MB
G1垃圾收集器测试完成

示例十:启用Epsilon垃圾收集器

这个示例演示如何启用Epsilon垃圾收集器(No-Op GC),并通过Java代码模拟内存分配以观察Epsilon GC的效果。Epsilon GC不会进行任何垃圾回收操作。

JVM启动参数
java -Xms1g -Xmx2g -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -jar MyApp.jar
Java代码
public class EpsilonGCTest {public static void main(String[] args) {System.out.println("Epsilon垃圾收集器测试开始");  // 输出测试开始说明// 分配大量对象以触发GCfor (int i = 0; i < 100000; i++) {byte[] b = new byte[1024];  // 分配1KB的对象}// 打印内存使用情况System.out.println("当前内存使用情况: ");System.out.println("最大堆内存: " + (Runtime.getRuntime().maxMemory() / 1024 / 1024) + "MB");  // 输出最大堆内存System.out.println("当前堆内存总量: " + (Runtime.getRuntime().totalMemory() / 1024 / 1024) + "MB");  // 输出当前堆内存总量System.out.println("空闲内存: " + (Runtime.getRuntime().freeMemory() / 1024 / 1024) + "MB");  // 输出空闲内存System.out.println("Epsilon垃圾收集器测试完成");  // 输出测试完成说明}
}

运行结果:

Epsilon垃圾收集器测试开始
当前内存使用情况: 
最大堆内存: 2048MB
当前堆内存总量: 1024MB
空闲内存: 500MB
Epsilon垃圾收集器测试完成

示例十一:调整线程栈大小

这个示例演示如何调整线程栈大小,并通过Java代码创建大量线程以观察效果。

JVM启动参数
java -Xss512k -XX:+PrintGCDetails -XX:+PrintGCDateStamps -jar MyApp.jar
Java代码
public class ThreadStackSizeTest {public static void main(String[] args) {System.out.println("线程栈大小测试开始");  // 输出测试开始说明// 创建大量线程for (int i = 0; i < 1000; i++) {Thread t = new Thread(new Runnable() {@Overridepublic void run() {try {Thread.sleep(1000);  // 线程休眠1秒} catch (InterruptedException e) {e.printStackTrace();}}});t.start();}System.out.println("线程创建完成");  // 输出线程创建完成说明// 打印当前线程数System.out.println("当前线程数: " + Thread.activeCount());  // 输出当前线程数System.out.println("线程栈大小测试完成");  // 输出测试完成说明}
}

运行结果:

线程栈大小测试开始
线程创建完成
当前线程数: 1001
线程栈大小测试完成

示例十二:调整元空间大小

这个示例演示如何调整元空间(Metaspace)大小,并通过Java代码验证这些设置的效果。

JVM启动参数
java -XX:MetaspaceSize=64m -XX:MaxMetaspaceSize=128m -XX:+PrintGCDetails -XX:+PrintGCDateStamps -jar MyApp.jar
Java代码
import java.lang.reflect.Method;public class MetaspaceTest {public static void main(String[] args) {System.out.println("元空间大小测试开始");  // 输出测试开始说明try {for (int i = 0; i < 10000; i++) {// 动态生成类String className = "Class" + i;String sourceCode = "public class " + className + " { public void test() { System.out.println(\"Hello from " + className + "\"); } }";Class<?> clazz = InMemoryCompiler.compile(className, sourceCode);// 使用反射调用生成的类的方法Method method = clazz.getMethod("test");method.invoke(clazz.newInstance());}} catch (Exception e) {e.printStackTrace();}System.out.println("元空间大小测试完成");  // 输出测试完成说明}
}

运行结果:

元空间大小测试开始
元空间大小测试完成

结论

JVM调优是一个复杂而重要的过程,需要结合具体的应用场景和系统性能数据进行调整。通过合理地设置堆内存大小、垃圾收集器以及新生代与老年代的比例,可以显著提升Java应用的性能。希望本文提供的指南和示例代码能够帮助你更好地理解和应用JVM调优技术,提高你的Java应用的性能和稳定性。

本文已收录于,我的技术网站 java-broke.site,有大厂完整面经,工作技术,架构师成长之路,等经验分享

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/49362.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【数据结构】详解二叉树及其操作

无论你觉得自己多么的了不起&#xff0c;也永远有人比你更强。&#x1f493;&#x1f493;&#x1f493; 目录 ✨说在前面 &#x1f34b;知识点一&#xff1a;二叉树的遍历 • &#x1f330;1.创建一棵二叉树 • &#x1f330;2.二叉树的遍历 •&#x1f525;前序遍历 •&a…

提升自身的国际影响力-香港服务器托管的优势

随着全球化的不断深入&#xff0c;中国企业正以前所未有的速度走向世界舞台&#xff0c;不仅在全球市场上展现其竞争力&#xff0c;更在寻求通过技术创新和服务优化来提升自身的国际影响力。在这一过程中&#xff0c;服务器的选择与托管成为了一个至关重要的环节。特别是在香港…

基于SpringBoot实现验证码功能

目录 一 实现思路 二 代码实现 三 代码汇总 现在的登录都需要输入验证码用来检测是否是真人登录&#xff0c;所以验证码功能在现在是非常普遍的&#xff0c;那么接下来我们就基于springboot来实现验证码功能。 一 实现思路 今天我们介绍的是两种主流的验证码&#xff0c;一…

使用php adodb5连接人大金仓数据库

打开php中的pgsql扩展 extensionpgsql使用adodb5连接kingbase数据库 <?php include("adodb5/adodb.inc.php"); $fox_dbtype pgsql; $fox_host 192.168.1.66; $fox_user system; $fox_pwd 123456; $fox_dbname testkingbase; $fox_port 54321;$dbNewADOCo…

级联目标检测 vs 单阶段检测:深度学习中的猫鼠游戏

级联目标检测 vs 单阶段检测&#xff1a;深度学习中的猫鼠游戏 目标检测是计算机视觉领域的一个核心问题&#xff0c;其目的是在图像中识别和定位一个或多个目标。随着深度学习技术的发展&#xff0c;目标检测方法经历了从传统算法到基于深度学习的方法的转变。目前&#xff0…

【JavaScript】对象属性

JS 对象的可枚举性指的是对象的某些属性是否可以被 JSON.stringify()、 for…in 循环、Object.keys()、Object.values() 和 Object.entries() ⽅法枚举到。 每个对象属性都有⼀个名字和一个属性描述符&#xff0c;这个属性描述符⾥⾯包括了该属性的许多特性&#xff0c;如可枚…

大数据技术--实验01-Hadoop的安装与使用【实测可行】

使用下面表中的软件版本进行配置&#xff1a; 准备好后&#xff0c;按照下面的步骤进行配置。 配置VMware网络 在VMWare主界面&#xff0c;点击“编辑”>“虚拟网络编辑”菜单进入虚拟网卡参数设置界面。选择VMnet8条目&#xff0c;点击“NAT设置”按钮后可以看到我们的VM…

学习unity官方的网络插件Netcode【一】

对bool值的个人理解&#xff1a; IsOwner&#xff1a;本地网络对象 IsLocalPlayer&#xff1a;本地网络玩家&#xff0c;&#xff08;本地网络玩家也是本地网络对象&#xff09; using Unity.Netcode; using UnityEngine; //个人理解&#xff1a;通过Rpc完成了一次客户端给服务…

【React Hooks原理 - createContext、useContext】

概述 在前面React Hooks系列介绍中我们知道React为了更好的处理不同生命周期的特殊处理&#xff0c;除了useContext这个Hooks之外的其他Hooks都拆为了Mount、Update两个阶段&#xff0c;而useContext内部并没有区分都是通过调用readContext来获取上下文的&#xff0c;下面就来…

微信小程序删除滑块 SwiperCell 自动收起 Van weapp van-swipe-cell 滑块自动收起 点击页面也自动收起滑块

在当前页面整个 view 中 给页面绑定 点击事件bindtap"onSwipeCellPage"给 van-swipe-cell 组件设置 id &#xff08;for循环可以添加 id"swip-cell-{{item.id}}" &#xff09;van-swipe-cell 组件 添加属性 当用户打开滑块时触发 bind:open"swiperCel…

Ajax原理-XMLHttpRequest、Promise以及封装简易的axios函数

这里写目录标题 一级目录二级目录三级目录 一、Ajax原理-XMLHttpRequest对象1.步骤 二、XMLHttpRequest-查询参数1.定义2.语法 二、XMLHttpRequest-数据提交1.需求2.核心 三、Promise1.定义2.好处3.三种状态 四、封装简易的axios1.需求&#xff1a;2.封装axios函数获取数据3.封…

使用UDP套接字编程详解【C语言】

UDP&#xff08;User Datagram Protocol&#xff0c;用户数据报协议&#xff09;是一种面向无连接的传输层协议&#xff0c;用于在计算机网络上发送数据。它与 TCP&#xff08;Transmission Control Protocol&#xff0c;传输控制协议&#xff09;相比具有轻量、高效的特点&…

英语(二)-我的学习方式

章节章节汇总我的学习方式历年真题作文&范文 目录 1、背单词 2、学语法 3、做真题 4、胶囊助学计划 写在最前&#xff1a;我是零基础&#xff0c;初二就听天书的那种。 本专栏持续更新学习资料 1、背单词 单词是基础&#xff0c;一定要背单词&#xff01;考纲要求要…

云动态摘要 2024-07-23

给您带来云厂商的最新动态,最新产品资讯和最新优惠更新。 最新优惠与活动 数据库上云优选 阿里云 2024-07-04 RDS、PolarDB、Redis、MongoDB 全系产品新用户低至首年6折起! [免费体验]智能助手ChatBI上线 腾讯云 2024-07-02 基于混元大模型打造,可通过对话方式生成可视化…

中文分词库 jieba 详细使用方法与案例演示

1 前言 jieba 是一个非常流行的中文分词库&#xff0c;具有高效、准确分词的效果。 它支持3种分词模式&#xff1a; 精确模式全模式搜索引擎模式 jieba0.42.1测试环境&#xff1a;python3.10.9 2 三种模式 2.1 精确模式 适应场景&#xff1a;文本分析。 功能&#xff1…

qt设置过滤器

1.创建事件过滤器类&#xff0c;在主窗口中安装事件过滤器 class PasteFilter : public QObject {Q_OBJECTpublic:PasteFilter(QObject *parent nullptr) : QObject(parent) {}protected:bool eventFilter(QObject *obj, QEvent *event) override {if (event->type() QEv…

【Zotero插件】Zotero Tag为文献设置阅读状态 win11下相关设置

【Zotero插件设置】Zotero Tag为文献设置阅读状态 win11下相关设置 1.安装Zotero Tag1.1安装1.2配置1.3 win11的相关设置1.3.1 字体安装 参考教程 2.支持排序的标注参考教程 1.安装Zotero Tag 1.1安装 Zotero Tag插件下载链接安装方法&#xff1a;Zotero–》工具–》附加组件…

googleTest 源码主线框架性分析——TDD 01

TDD&#xff0c;测试驱动开发&#xff0c;英文全称Test-Driven Development&#xff0c;简称TDD&#xff0c;是一种不同于传统软件开发流程的新型的开发方法。它要求在编写某个功能的代码之前先编写测试代码&#xff0c;然后只编写使测试通过的功能代码&#xff0c;通过测试来推…

苹果和乔布斯的传奇故事,从车库创业到万亿市值巨头

苹果公司的品牌故事&#xff0c;就像一部充满创新、挑战与辉煌的科幻大片&#xff0c;让人目不暇接。 故事始于1976年&#xff0c;那时&#xff0c;年轻的史蒂夫乔布斯与斯蒂夫沃兹尼亚克在加州的一个简陋车库里&#xff0c;用他们的热情和智慧&#xff0c;捣鼓出了世界上第一…

python学习之闭包与装饰器

一、闭包 闭包允许一个函数访问并操作函数外部的变量&#xff08;即父级作用域中的变量&#xff09;&#xff0c;即使在该函数外部执行。 特性&#xff1a; (1)外部函数嵌套内部函数。 (2)外部函数可以返回内部函数。 (3)内部函数可以访问外部函数的局部变量。 def out()…