JVM的GC详解
获取GC日志方式大抵有两种
第一种就是设定JVM参数在程序启动时查看,具体的命令参数为:
-XX:+PrintGCDetails # 打印GC日志
-XX:+PrintGCTimeStamps # 打印每一次触发GC时发生的时间
第二种则是在服务器上监控:使用jstat查看,如下所示,命令格式为jstat -gc pid 输出间隔时长 输出次数
,例如笔者希望每隔1秒输出1次,并且打印5次,对应的指令如下:
jstat -gc 21608 1000 5
public static void main(String[] args) {//分配1M内存空间byte[] bytes = new byte[1024 * 1024];//触发minor gc,剩余512k,然后将1M空间存放至新生代,堆空间大约剩下1.5Mbytes = new byte[1024 * 1024];//分配至新生代约2.5Mbytes = new byte[1024 * 1024];//新生代空间不足,触发full gc,新生代空间全回收,并执行CMS GC,完成后将对象存放至新生代byte[] byte2 = new byte[2 * 1024 * 1024];}
设置JVM配置参数指明新生代、老年代堆空间大小为5M,并指明新生代Eden和survivor区的比例为8:1:1,同时我们也指定的新生代和老年代垃圾回收算法分别是ParNewGC和CMS:
-XX:NewSize=5M -XX:MaxNewSize=5M -XX:InitialHeapSize=10M -XX:MaxHeapSize=10M -XX:SurvivorRatio=8 -XX:PretenureSizeThreshold=10M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps
- -XX:NewSize=5M:设置新生代的初始大小为 5MB。
- -XX:MaxNewSize=5M:设置新生代的最大大小为 5MB。
- -XX:InitialHeapSize=10M:设置 JVM 堆的初始大小为 10MB。
- -XX:MaxHeapSize=10M:设置 JVM 堆的最大大小为 10MB。
- -XX:SurvivorRatio=8:设置 Eden 区与 Survivor 区的比例为 8,即 Eden 占用 8/10 的新生代空间,两个 Survivor 各占 1/10。
- -XX:PretenureSizeThreshold=10M:设置对象直接进入老年代的阈值为 10MB,超过这个大小的对象会直接分配到老年代。
- -XX:+UseParNewGC:启用并行新生成收集器(Parallel New Generation Collector),用于多线程环境下的新生代垃圾回收。
- -XX:+UseConcMarkSweepGC:启用并发标记清除收集器(Concurrent Mark Sweep Collector),用于多线程环境下的老年代垃圾回收。
- -XX:+PrintGCDetails:打印详细的垃圾回收日志信息。
- -XX:+PrintGCTimeStamps:在垃圾回收日志中添加时间戳。
GC过程:
-
首先代码执行到byte[] bytes = new byte[1024 * 1024];,此时新生代空间充裕,没有任何输出。
-
执行第二行代码bytes = new byte[1024 * 1024];再次进程内存分配时,发现新生代空间不足出现以此minor gc,对应输出结果如下,
2.938: [GC (Allocation Failure) 2.938: [ParNew: 3348K->512K(4608K), 0.0016244 secs] 3348K->1692K(9728K), 0.0016904 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
我们大体可以看出GC原因是Allocation Failure即新生代不能分配对象,触发一次新生代GC,新生代GC前后空间由3348K变为512K,整堆空间由3348K变为1692K,最后输出了GC耗时、系统响应耗时以及应用程序暂停时间
完成上述GC,将1M的数组存放至新生代,此时新生代的堆空间大约是1M:
-
然后第三行再次分配数组,新生代空间充裕,直接存入:
-
最后一次分配2M数组时,新生代空间不足且空间分配担保失败,直接触发FULL GC,从日志中我们可以看到minor gc直接将上述的所有字节数组都回收了:
9.689: [GC (Allocation Failure) 9.689: [ParNew: 2626K->0K(4608K), 0.0021520 secs] 3806K->2746K(9728K), 0.0021903 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
-
最后就是CMS老年代GC,首先进行初始标记阶段该阶段为STW并找到所有的GC root,从日志中我们看到老年代使用的容量为2718K且总容量为5120K,后面的4766K(9728K)标记为当前堆的实际大小和总容量:
2.057: [GC (CMS Initial Mark) [1 CMS-initial-mark: 2718K(5120K)] 4766K(9728K), 0.0005690 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
-
然后进入并发标记阶段该阶段不会STW,先是CMS-concurrent-mark标记gc root可达对象,然后CMS-concurrent-preclean重新并发扫描进入到老年代的对象,最后时CMS-concurrent-abortable-preclean该阶段并发运行至eden区空间占用率达到满意:
2.058: [CMS-concurrent-mark-start] 2.059: [CMS-concurrent-mark: 0.001/0.001 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 2.059: [CMS-concurrent-preclean-start] 2.059: [CMS-concurrent-preclean: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 2.059: [CMS-concurrent-abortable-preclean-start]CMS: abort preclean due to time 7.163: [CMS-concurrent-abortable-preclean: 0.005/5.105 secs] [Times: user=0.00 sys=0.00, real=5.10 secs]
-
最后就到了最终标记阶段,该阶段会STW,从日志输出可以看出新生代占用2048k,当前这个重新标记阶段Rescan 花费了0.0004620 secs,其余就是处理弱引用、卸载无用的类以及清理元数据等花费时间和耗时:
7.164: [GC (CMS Final Remark) [YG occupancy: 2048 K (4608 K)]7.164: [Rescan (parallel) , 0.0004620 secs]7.164: [weak refs processing, 0.0001727 secs]7.164: [class unloading, 0.0005772 secs]7.165: [scrub symbol table, 0.0011975 secs]7.166: [scrub string table, 0.0003404 secs][1 CMS-remark: 2718K(5120K)] 4766K(9728K), 0.0030256 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
-
最后就是并发的清理垃圾会重置标记,等待下一个周期的GC:
7.167: [CMS-concurrent-sweep-start] 7.168: [CMS-concurrent-sweep: 0.001/0.001 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 7.168: [CMS-concurrent-reset-start] 7.168: [CMS-concurrent-reset: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
-
最后我们查看内存使用情况可以看到,新生代的2M就是我们最后分配的数组,在eden区,而老年代使用了1677K:
Heappar new generation total 4608K, used 2089K [0x00000000ff600000, 0x00000000ffb00000, 0x00000000ffb00000)eden space 4096K, 51% used [0x00000000ff600000, 0x00000000ff80a558, 0x00000000ffa00000)from space 512K, 0% used [0x00000000ffa00000, 0x00000000ffa00000, 0x00000000ffa80000)to space 512K, 0% used [0x00000000ffa80000, 0x00000000ffa80000, 0x00000000ffb00000)concurrent mark-sweep generation total 5120K, used 1677K [0x00000000ffb00000, 0x0000000100000000, 0x0000000100000000)Metaspace used 3124K, capacity 4486K, committed 4864K, reserved 1056768Kclass space used 327K, capacity 386K, committed 512K, reserved 1048576K
频繁的gc
- Minor GC:发生在年轻代的空间回收,包含eden和survivor,也叫做Young GC。
- Major GC:在老年代堆区进行空间回收。
- Full GC:清理所有堆区的内存空间的垃圾内存,包括年轻代和老年代。
频繁的 minor gc 和major gc
public static void main(String[] args) throws Exception {while (true) {//分配3M数组byte[] bytes = new byte[1024 * 1024];bytes = new byte[1024 * 1024];bytes = new byte[1024 * 1024];//创建2M的新对象触发GCbyte[] byte2 = new byte[2 * 1024 * 1024];Thread.sleep(1000);}}
设置该程序的堆内存新生代为5M,按照8:1:1的比例分配,这也就意为着Eden区内存大小为4M,然后S区分别是512K,这也就意味着在待分配对象加Eden区堆空间超过4M就会触发minor gc:
为了演示年轻代的回收行为,我们需要在对这个应用程序的年轻代堆内存改为5M,且Eden区和S区的比例为8:1:1,同时也打印GC日志信息:
-XX:NewSize=5M -XX:MaxNewSize=5M -XX:InitialHeapSize=10M -XX:MaxHeapSize=10M -XX:SurvivorRatio=8 -XX:PretenureSizeThreshold=10M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps
输出结果如下,GC日志显示每秒基本都会触发一次Minor GC,进而间接导致频繁的major gc:
结合配置可知,我们频繁分配对象导致新生代进行频繁的GC,又因为S区大小无法容纳存活的对象,进而使得这些对象提前进入老年代,导致major GC也随之频繁,所以 解决 的办法也比较简单,按照等比例调整大堆空间,即将新生代堆空间调整至10M,保证S区各有2M空间以容纳新生代存活的对象:
-XX:NewSize=10M -XX:MaxNewSize=10M -XX:InitialHeapSize=100M -XX:MaxHeapSize=100M -XX:SurvivorRatio=8 -XX:PretenureSizeThreshold=10M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps
可以看到经过调整之后,基本上Minor gc就能解决问题:
将年轻代空间调大,是否会更加耗时?
答案是不会的,原因如以:
- JVM操作本质上都是内存操作,相对而言不会太慢。
- 将一次GC的时间拆分为t1和t2,t1是扫描年轻代空间是否有垃圾的时间,这个时间的几乎可以忽略不计。而t2则是将eden空间存活的对象复制到survivor区的时间,这个复制操作则是t1时间的10倍。
- 由此可以看出,避免耗时的正确做法是合理评估新生代堆空间,减少非必要的复制操作,所以说调整新生代的空间并不会导致进一步的耗时问题。
频繁的FULL GC
模拟一个场景,我们的应用中有一个定时任务,这个定时任务每隔1s会想另一个定时任务线程池中提交100个任务,每个任务都会针对Obj 对象进行方法调用:
@Component
public class Task {private static Logger logger = LoggerFactory.getLogger(Task.class);private static final ScheduledThreadPoolExecutor executor =new ScheduledThreadPoolExecutor(50,new ThreadPoolExecutor.DiscardOldestPolicy());private static class Obj {private String name = "name";private int age = 18;private String gender = "man";private LocalDate birthday = LocalDate.MAX;public void func() {//这个方法什么也不做}//返回count个Obj对象private static List<Obj> getObjList(int count) {List<Obj> objList = new ArrayList<>(count);for (int i = 0; i != count; ++i) {objList.add(new Obj());}return objList;}}@Scheduled(cron = "0/1 * * * * ? ") //每1秒执行一次public void execute() {logger.info("1s一次定时任务");//向线程池提交100个任务Obj.getObjList(100).forEach(i -> executor.scheduleWithFixedDelay(i::func, 2, 3, TimeUnit.SECONDS));}
}
完成后我们设置下面这段JVM参数后,将其启动:
-Xms20M -Xmx20M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps
不久后,控制台出现频繁的full gc,如果在生产环境,频繁的full gc导致stw会导致系统吞吐量下降:
1288.133: [Full GC (Allocation Failure) 1288.133: [CMS1288.142: [CMS-concurrent-preclean: 0.012/0.012 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] (concurrent mode failure): 13695K->13695K(13696K), 0.0610050 secs] 19839K->19836K(19840K), [Metaspace: 29026K->29026K(1077248K)], 0.0610521 secs] [Times: user=0.06 sys=0.00, real=0.06 secs]
1288.258: [Full GC (Allocation Failure) 1288.258: [CMS: 13695K->13695K(13696K), 0.0612134 secs] 19839K->19836K(19840K), [Metaspace: 29026K->29026K(1077248K)], 0.0612676 secs] [Times: user=0.06 sys=0.00, real=0.06 secs]
1288.320: [GC (CMS Initial Mark) [1 CMS-initial-mark: 13695K(13696K)] 19836K(19840K), 0.0041303 secs] [Times: user=0.03 sys=0.00, real=0.00 secs]
排查思路
定位到程序号后,使用jstat -gc pid10000 10
观察其gc情况,可以看到每隔10s,就会增加大量的full gc:
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
640.0 640.0 0.0 640.0 5504.0 665.5 13696.0 11176.2 31488.0 28992.6 4352.0 3889.5 39 0.084 15 0.100 0.184
640.0 640.0 0.0 640.0 5504.0 1487.2 13696.0 11176.2 31488.0 28992.6 4352.0 3889.5 39 0.084 25 0.142 0.227
640.0 640.0 0.0 640.0 5504.0 1697.8 13696.0 11176.2 31488.0 28992.6 4352.0 3889.5 39 0.084 35 0.185 0.269
再查看jmap -heap pid
查看堆区使用情况,可以看到老年代的使用率还是蛮高的:
Attaching to process ID 26176, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.212-b10using parallel threads in the new generation.
using thread-local object allocation.
Concurrent Mark-Sweep GCHeap Configuration:MinHeapFreeRatio = 40MaxHeapFreeRatio = 70MaxHeapSize = 20971520 (20.0MB)NewSize = 6946816 (6.625MB)MaxNewSize = 6946816 (6.625MB)OldSize = 14024704 (13.375MB)NewRatio = 2SurvivorRatio = 8MetaspaceSize = 21807104 (20.796875MB)CompressedClassSpaceSize = 1073741824 (1024.0MB)MaxMetaspaceSize = 17592186044415 MBG1HeapRegionSize = 0 (0.0MB)Heap Usage:
New Generation (Eden + 1 Survivor Space):capacity = 6291456 (6.0MB)used = 5088288 (4.852569580078125MB)free = 1203168 (1.147430419921875MB)80.87615966796875% used
Eden Space:capacity = 5636096 (5.375MB)used = 5088288 (4.852569580078125MB)free = 547808 (0.522430419921875MB)90.28036428052326% used
From Space:capacity = 655360 (0.625MB)used = 0 (0.0MB)free = 655360 (0.625MB)0.0% used
To Space:capacity = 655360 (0.625MB)used = 0 (0.0MB)free = 655360 (0.625MB)0.0% used
concurrent mark-sweep generation:capacity = 14024704 (13.375MB)used = 13819664 (13.179458618164062MB)free = 205040 (0.1955413818359375MB)98.53800836010514% used12064 interned Strings occupying 1120288 bytes.
在排除内存泄漏的问题后,我们通过jmap定位进程中导致是什么对象导致老年代堆区被大量占用:
jmap -histo 7476 | head -n 20
可以看到前20名中的对象都是和定时任务相关,有一个Task$Obj对象非常抢眼,很明显就是因为它的数量过多导致的,此时我们就可以通过定位代码确定如何解决,常见方案无非是: 优化代码、增加空间两种方式,一般来说我们都会采用代码优化的方式去解决。
num #instances #bytes class name
----------------------------------------------1: 50760 3654720 java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask2: 30799 2901552 [C3: 88986 2847552 java.util.concurrent.locks.AbstractQueuedSynchronizer$Node4: 50700 1622400 com.example.jstackTest.Task$Obj5: 50760 1218240 java.util.concurrent.Executors$RunnableAdapter6: 50700 811200 com.example.jstackTest.Task$$Lambda$587/16055533137: 6391 707928 java.lang.Class8: 29256 702144 java.lang.String9: 13577 434464 java.util.concurrent.ConcurrentHashMap$Node10: 6363 341016 [Ljava.lang.Object;11: 1722 312440 [B12: 3414 230424 [I13: 4 210680 [Ljava.util.concurrent.RunnableScheduledFuture;14: 5223 208920 java.util.LinkedHashMap$Entry15: 2297 202136 java.lang.reflect.Method16: 2262 193760 [Ljava.util.HashMap$Node;17: 5668 181376 java.util.HashMap$Node
而本次问题也很明显,任务是一个个提交到定时任务线程池中,是由于定时任务队列DelayedWorkQueue不断堆积任务导致内存被打满。所以最终改成将一个批处理一次性提交到定时任务中立刻将这一批对象回收从而避免耗时任务堆积一堆对象:
@Scheduled(cron = "0/1 * * * * ? ") //每1秒执行一次public void execute() {logger.info("1s一次定时任务");//向线程池提交100个任务executor.scheduleWithFixedDelay(() -> {Obj.getObjList(100).forEach(i -> i.func());}, 2, 3, TimeUnit.SECONDS);}
频繁FULL GC的原因和解决对策
总的来说原因可以频繁FULL GC分为3个:
- 用户频繁调用System.gc():这种情况需要修改代码即可,我们不该频繁调用这个方法的。
- 老年区空间过小:视情况适当扩大空间。
- 大对象过多:这种情况视情况决定是扩大老年代空间或者将大对象拆分。
一般来说,我们优先考虑调整堆内存空间,其次才是针对业务逻辑的代码处理进行更进一步的优化。
相关文章:

JVM的GC详解
获取GC日志方式大抵有两种 第一种就是设定JVM参数在程序启动时查看,具体的命令参数为: -XX:PrintGCDetails # 打印GC日志 -XX:PrintGCTimeStamps # 打印每一次触发GC时发生的时间第二种则是在服务器上监控:使用jstat查看,如下所示,命令格式为jstat -gc…...

【开源免费】基于Vue和SpringBoot的校园网上店铺系统(附论文)
本文项目编号 T 187 ,文末自助获取源码 \color{red}{T187,文末自助获取源码} T187,文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…...

测压表压力表计量表针头针尾检测数据集VOC+YOLO格式4862张4类别
数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):4862 标注数量(xml文件个数):4862 标注数量(txt文件个数):4862 …...
Vue 3 30天精进之旅:Day 12 - 异步操作
在现代前端开发中,异步操作是一个非常常见的需求,例如从后端API获取数据、进行文件上传等任务。Vue 3 结合组合式API和Vuex可以方便地处理这些异步操作。今天我们将重点学习如何在Vue应用中进行异步操作,包括以下几个主题: 异步操…...

【网络】3.HTTP(讲解HTTP协议和写HTTP服务)
目录 1 认识URL1.1 URI的格式 2 HTTP协议2.1 请求报文2.2 响应报文 3 模拟HTTP3.1 Socket.hpp3.2 HttpServer.hpp3.2.1 start()3.2.2 ThreadRun()3.2.3 HandlerHttp() 总结 1 认识URL 什么是URI? URI 是 Uniform Resource Identifier的缩写&…...
[paddle] 矩阵相关的指标
行列式 det 行列式定义参考 d e t ( A ) ∑ i 1 , i 2 , ⋯ , i n ( − 1 ) σ ( i 1 , ⋯ , i n ) a 1 , i 1 a 2 , i 2 , ⋯ , a n , i n det(A) \sum_{i_1,i_2,\cdots,i_n } (-1)^{\sigma(i_1,\cdots,i_n)} a_{1,i_1}a_{2,i_2},\cdots, a_{n,i_n} det(A)i1,i2,⋯,in…...

docker部署SpringBoot项目简单流程
一、docker基础命令理解学习 1、常见命令 docker启动之前要关闭防火墙systemctl stop firewalld # 关闭防火墙systemctl disable firewalld # 禁止开机启动防火墙systemctl start docker # 启动docker服务systemctl stop docker # 停止docker服务systemctl restart docker # …...
Python学习——函数参数详解
Python中的函数参数传递机制允许多种灵活的参数类型,可以根据需求灵活配置参数,这使得函数具有更强大的扩展性和适应性。以下是对各类参数类型的详细说明: 1. 定义函数的不同参数类型 1.1 位置参数 定义方式:def func(a, b2) 特…...

Chromium132 编译指南 - Android 篇(一):编译前准备
1. 引言 欢迎来到《Chromium 132 编译指南 - Android 篇》系列的第一部分。本系列指南将引导您逐步完成在 Android 平台上编译 Chromium 132 版本的全过程。Chromium 作为一款由 Google 主导开发的开源浏览器引擎,为众多现代浏览器提供了核心驱动力。而 Android 作…...
.Net / C# 繁体中文 与 简体中文 互相转换, 支持地方特色词汇
版本号 Nuget 搜索 “OpenCCNET”, 注意别找错, 好多库的名字都差不多 支持 “繁,简” 的互相转换, 支持多个地区常用词汇的转换, 还支持 日文的新旧转换. OpenCC 在 .Net 中的实现 https://github.com/CosineG/OpenCC.NET <PackageReference Include"OpenCCNET"…...
Java泛型深度解析(JDK23)
第一章 泛型革命 1.1 类型安全的进化史 前泛型时代的类型转换隐患 代码的血泪史(Java 1.4版示例): List rawList new ArrayList(); rawList.add("Java"); rawList.add(Integer.valueOf(42)); // 编译通过// 灾难在运行时爆发…...

【贪心算法篇】:“贪心”之旅--算法练习题中的智慧与策略(一)
✨感谢您阅读本篇文章,文章内容是个人学习笔记的整理,如果哪里有误的话还请您指正噢✨ ✨ 个人主页:余辉zmh–CSDN博客 ✨ 文章所属专栏:贪心算法篇–CSDN博客 文章目录 一.贪心算法1.什么是贪心算法2.贪心算法的特点 二.例题1.柠…...
AJAX XML
AJAX XML 引言 随着互联网技术的不断发展,Web应用对用户交互性和实时性的要求越来越高。AJAX(Asynchronous JavaScript and XML)技术的出现,为Web应用开发提供了强大的支持。AJAX技术允许Web应用在不重新加载整个页面的情况下,与服务器进行异步通信。XML作为数据传输格式…...
踏入编程世界的第一个博客
我,一个双非一本大一新生,普通的不能再普通了,面对宏伟庞大的计算机世界仍显得举手无措,我自以为自身仍有些许骨气,不想普普通通,甚是浑浑噩噩的度过四年大学,经历了高考的打击,双非…...

2025年1月22日(网络编程 udp)
系统信息: ubuntu 16.04LTS Raspberry Pi Zero 2W 系统版本: 2024-10-22-raspios-bullseye-armhf Python 版本:Python 3.9.2 已安装 pip3 支持拍摄 1080p 30 (1092*1080), 720p 60 (1280*720), 60/90 (640*480) 已安装 vim 已安装 git 学习…...
数据结构与算法之栈: LeetCode 641. 设计循环双端队列 (Ts版)
设计循环双端队列 https://leetcode.cn/problems/design-circular-deque/description/ 描述 设计实现双端队列。 实现 MyCircularDeque 类: MyCircularDeque(int k) :构造函数,双端队列最大为 k 。boolean insertFront():将一个元素添加到双端队列头部…...
从零开始学 HTML:构建网页的基本框架与技巧
系列文章目录 01-从零开始学 HTML:构建网页的基本框架与技巧 文章目录 系列文章目录前言一、HTML 文档的基本框架1.1 <!DOCTYPE html>、<html>、<head>、<body> 标签解析1.1.1 <!DOCTYPE html> 标签1.1.2 <html> 标签1.1.3 &l…...

一些杂记2
1.#define 1.1定义 #define 是一个预处理指令,用于定义宏 宏,是预处理阶段(在编译之前)由预处理器处理的代码片段 1.2使用 1.2.1 #define 可以定义常量 #define PI 3.14159 1.2.2 #define 可以定义宏函数 #define SQUARE(x) ((…...

C语言 --- 分支
C语言 --- 分支 语句分支语句含义if...else语句单分支if语句语法形式 双分支 if-else 语句语法形式 悬空else含义问题描述 多分支 if-else 语句语法形式 switch...case语句含义语法形式 总结 💻作者简介:曾与你一样迷茫,现以经验助你入门 C 语…...

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】2.10 ndarray内存模型:从指针到缓存优化
2.10 ndarray内存模型:从指针到缓存优化 目录 #mermaid-svg-p0zxLYqAnn59O2Xe {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-p0zxLYqAnn59O2Xe .error-icon{fill:#552222;}#mermaid-svg-p0zxLYqAnn59O…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...

19c补丁后oracle属主变化,导致不能识别磁盘组
补丁后服务器重启,数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后,存在与用户组权限相关的问题。具体表现为,Oracle 实例的运行用户(oracle)和集…...

K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

转转集团旗下首家二手多品类循环仓店“超级转转”开业
6月9日,国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解,“超级…...
【HTML-16】深入理解HTML中的块元素与行内元素
HTML元素根据其显示特性可以分为两大类:块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...
鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南
1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...
AGain DB和倍数增益的关系
我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...