Linux中《进程状态--进程调度--进程切换》详细介绍
目录
- 进程状态
- Linux内核源代码怎么说
- 运行&&阻塞&&挂起
- 内核链表
- 进程状态查看
- Z(zombie)-僵尸进程
- 僵尸进程危害
- 孤儿进程
- 进程优先级
- 进程切换
- Linux2.6内核进程O(1)调度队列
进程状态
Linux内核源代码怎么说
为了弄明白正在运⾏的进程是什么意思,我们需要知道进程的不同状态。⼀个进程可以有几个状态(在Linux内核里,进程有时候也叫做任务)。
进程状态就是task_struct内的一个整形变量,也是一个标记位(宏定义的)。
状态决定了当前系统如何处理这个进程。
运行&&阻塞&&挂起
运行状态
该进程在调度队列中或者正在被CPU执行。
阻塞状态
等待某种设备或资源就绪(如果不就绪,我的进程就不会被调度)。
运行状态转化为阻塞状态,本质上就是把PCB链入到不同的数据结构当中!只有在运行队列中,进程才会被调度,但是现在进程在设备队列中,那么如何再被CPU调度呢?
总结:进程状态变化的表现之一,就是CPB要在不同的数据结构之间进行流动,本质都是数据结构的增删查改。
挂起状态
当内存资源不足时,将wait_queue里的进程的代码和数据唤出到磁盘当中swap交换分区。如果次数键盘就绪了,OS会把磁盘当中该PCB的代码和数据再重新加载到内存,构建指针映射,这个也叫做唤入。我们把这个称为阻塞挂起,运行挂起也是同样的道理。
内核链表

下⾯的状态在kernel源代码⾥定义:
/*
*The task state array is a strange “bitmap” of
*reasons to sleep. Thus “running” is zero, and
*you can test for combinations of others with
*simple bit tests.
*/
static const char *const task_state_array[] = {
"R (running)", /*0 */ //运行
"S (sleeping)", /*1 */ //阻塞
"D (disk sleep)", /*2 */ //阻塞
"T (stopped)", /*4 */ //暂停
"t (tracing stop)", /*8 */ //暂停(追踪状态),例如debug的调试状态下,设置断点,进程被站暂停了
"X (dead)", /*16 */ //死亡
"Z (zombie)", /*32 */ //僵尸 ->为了获取退出信息
};
• R运⾏状态(running): 并不意味着进程⼀定在运⾏中,它表明进程要么是在运⾏中要么在运⾏队列⾥。
• S睡眠状态(sleeping): 意味着进程在等待事件完成(这⾥的睡眠有时候也叫做可中断睡眠,浅睡眠。ctrl+c是可以杀掉这个进程的。
(interruptible sleep)(浅睡眠))。
• D磁盘休眠状态(Disk sleep):有时候也叫不可中断睡眠状态(uninterruptible sleep),深度睡眠,在这个状态的进程通常会等待IO的结束,不可中断睡眠状态的进程不能被杀掉,只能等待它自己被唤醒,这样可以防止数据的丢失。例如:当进程往磁盘里写入内容时,此时如果内存资源严重不足时,需要杀掉进程时,该进程处于S状态,可以被杀掉,等待磁盘写入完数据,如果杀掉该进程,那么这个内容到底是写完了?还是没写完?我都不知道,磁盘也不知道该如何处理这一段内容,所以可能会存在数据丢失,此时,把该进程的状态修改为D,此时该进程不对任何杀掉的动作进行响应,OS就不会杀掉它。• T停⽌状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停⽌(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运⾏,如果进行非法操作,系统可以暂停进程,止损。
t (tracing stop): 暂停(追踪状态),例如debug的调试状态下,设置断点,进程被暂停了。
• X死亡状态(dead):这个状态只是⼀个返回状态,你不会在任务列表⾥看到这个状态。
插播一个关于内核结构申请的小的知识点:要把释放的PCB回收时,可以用unuse链表把要回收的PCB节点链接起来,等创建新进程时,需要创建PCB节点时,把unuse链表里的PCB拿来用,这种技术叫做slab。数据结构对象的缓存,可以加速创建和释放进程的速度。
进程状态查看
ps aux / ps axj
- a:显⽰⼀个终端所有的进程,包括其他⽤⼾的进程。
- x:显⽰没有控制终端的进程,例如后台运⾏的守护进程。
- j:显⽰进程归属的进程组ID、会话ID、⽗进程ID,以及与作业控制相关的信息
- u:以⽤⼾为中⼼的格式显⽰进程信息,提供进程的详细信息,如⽤⼾、CPU和内存使⽤情况等
Z(zombie)-僵尸进程
- 僵死状态(Zombies)是⼀个⽐较特殊的状态。当进程退出,进程的代码和数据被释放,但是PCB不会被释放,此时父进程还没有从子进程的PCB里获取退出信息。
- 僵死进程会以终⽌状态保持在进程表中,并且会⼀直在等待⽗进程读取退出状态代码。
- 所以,只要⼦进程退出,⽗进程还在运⾏,但⽗进程没有读取⼦进程状态,⼦进程进⼊Z状态。
- 如果父进程一直不管,不回收,不获取子进程的退出信息,那么Z(僵尸状态)会一直存在,此时,会造成内存泄漏!!!

僵尸进程危害
- 进程的退出状态必须被维持下去,因为他要告诉关⼼它的进程(⽗进程),你交给我的任务,我办的怎么样了。可⽗进程如果⼀直不读取,那⼦进程就⼀直处于Z状态?是的!
- 维护退出状态本⾝就是要⽤数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,换句话说,Z状态⼀直不退出,PCB⼀直都要维护?是的!
- 那⼀个⽗进程创建了很多⼦进程,就是不回收,是不是就会造成内存资源的浪费?是的!因为数据结构对象本⾝就要占⽤内存,想想C中定义⼀个结构体变量(对象),是要在内存的某个位置进⾏开辟空间!
- 内存泄漏?是的!
孤儿进程
- ⽗进程如果提前退出,那么⼦进程后退出,进⼊Z之后,那该如何处理呢?
- ⽗进程先退出,⼦进程就称之为“孤⼉进程”
- 孤⼉进程被1号init进程领养,当然要有init进程回收喽。1号init进程我们可以理解为操作系统。
有1号进程,那么有0号进程吗?
有的,只不过刚开机时,被1号进程给替换掉了。
为什么要领养?
为了回答这个问题,我们就要想一想,如果不领养会怎么样?子进程退出后,进入僵尸状态,如果没有父进程回收子继承,那么会造成内存泄漏。hou
注意:变成孤儿进程之后,被1号进程领养,子进程会自动变成后台进程,使用ctrl+c杀不掉它的,但是后台进程可以向前台进程打印信息。
进程优先级
基本概念
- cpu资源分配的先后顺序,就是指进程的优先权(priority)。
- 优先权⾼的进程有优先执⾏权利。配置进程优先权对多任务环境的linux很有⽤,可以改善系统性能。
- 还可以把进程运⾏到指定的CPU上,这样⼀来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能。
总结:进程优先级就是进程得到资源的先后顺序。
为什么会有优先级这个概念?
CPU太少了,内存太少了,进程又多,目标资源稀缺,导致需要通过优先级来确认谁先谁后的问题。
优先级VS权限
优先级:能得到这个资源,只不过是先后的问题。
权限:能不能得到这个资源。
查看系统进程
在linux或者unix系统中,⽤ps ‒l命令则会类似输出以下⼏个内容:
我们很容易注意到其中的⼏个重要信息,有下:
• UID : 代表执⾏者的⾝份,user id。
Linux系统中,访问任何资源,都是进程代表用户去访问的。进程当中的UID代表的是该进程是被哪个用户启动的。OS中用户名字是给我们看的,系统里面区分用户是用的UID,当进程去访问文件的时候,OS会把进程的UID和文件的用户的权限进行对比,查看该进程是否有权限。
• PID : 代表这个进程的代号
• PPID :代表这个进程是由哪个进程发展衍⽣⽽来的,亦即⽗进程的代号
• PRI :代表这个进程可被执⾏的优先级,其值越⼩越早被执⾏,默认是80
• NI :代表这个进程的nice值,进进程优先级的修正数据,默认值为0
进程真实的优先级 = PRI(默认) + NI
修改进程优先级
1.
top->r->pid
2.
使用 nice 命令
nice 命令用于在启动新进程时设置其优先级。其语法为:
nice -n <nice_value> <command>
3.
使用 renice 命令
renice 命令用于调整已经运行中的进程的优先级。其语法为:
renice <nice_value> -p <pid>
4
使用 setpriority() 系统调用#include <sys/time.h> #include <sys/resource.h> int setpriority(int which, id_t who, int value); 参数: which:指定要调整优先级的对象类型,可以是 PRIO_PROCESS(进程)、PRIO_PGRP(进程组)或 PRIO_USER(用户)。 who:指定要调整优先级的对象 ID。如果 which 是 PRIO_PROCESS,则 who 是进程 ID;如果是 PRIO_PGRP,则 who 是进程组 ID;如果是 PRIO_USER,则 who 是用户 ID。 value:新的 nice 值,范围是 -20 到 19。
PRI and NI
• PRI也还是⽐较好理解的,即进程的优先级,或者通俗点说就是程序被CPU执⾏的先后顺序,此值越⼩进程的优先级别越⾼。
• 那NI呢?就是我们所要说的nice值了,其表⽰进程可被执⾏的优先级的修正数值。
• PRI值越⼩越快被执⾏,那么加⼊nice值后,将会使得PRI变为:PRI(new)=PRI(old)+nice
• 这样,当nice值为负值的时候,那么该程序将会优先级值将变⼩,即其优先级会变⾼,则其越快被执⾏。
• 所以,调整进程优先级,在Linux下,就是调整进程nice值。
PRI vs NI
需要强调⼀点的是,进程的nice值不是进程的优先级,他们不是⼀个概念,但是进程nice值会影响到进程的优先级变化。可以理解nice值是进程优先级的修正修正数据。
优先级的极值问题
nice的范围是[-20,19],也就是说,PRI的范围是[60,99],幅度为40。考虑到公平性,幅度不能太大,优先级设立的不合理,会导致优先级低的进程,长时间得不到CPU的资源,进而导致进程饥饿。
查看进程优先级的命令
⽤top命令更改已存在进程的nice值:
• top
• 进⼊top后按“r”‒>输⼊进程PID‒>输⼊nice值
注意:
其他调整优先级的命令:nice,renice
进程切换
CPU上下⽂切换:其实际含义是任务切换, 或者CPU寄存器切换。当多任务内核决定运⾏另外的任务时, 它保存正在运⾏任务的当前状态, 也就是CPU寄存器中的全部内容。这些内容被保存在任务⾃⼰的堆栈中, ⼊栈⼯作完成后就把下⼀个将要运⾏的任务的当前状况从该任务的栈中重新装⼊CPU寄存器,并开始下⼀个任务的运⾏, 这⼀过程就是context switch。

结论:
- 寄存器:保存正在运行的进程的临时数据,是CPU内部保存数据的临时空间。
- 寄存器 != 寄存器里的数据。寄存器是一段空间,只有1份,寄存器里的数据,是内容,变化的,可以有多份。
- 进程切换最核心的,就是保存和恢复当前进程的硬件上下文数据,即CPU内寄存器的内容。
- 当前进程把自己的硬件上下文数据保存到了
task_struct里,在结构体里可以命名一些寄存器的变量,来存放相关数据,当进程被切换时,找到task_struct里的数据,把数据放到CPU里的寄存器里。由于task_struct的内容很多,所以当代OS把硬件上下文数据独立保存了TSS里,没有放在task_struct里了,但是task_struct存放了TSS的地址。
- 如何区分全新的进程和已经被调度过的进程?可以使用标记位(int isrunning),如果是新进程,isrunning的值为0,如果被调度过,isrunning为1.
- 时间⽚:当代计算机都是分时操作系统,每一个进程都有它合适的时间⽚(其实就是⼀个计数器)。时间⽚到达,进程就被操作系统从CPU中剥离下来。
Linux2.6内核进程O(1)调度队列
背景知识:
调度器:是由调度和切换共同构成的,调度和切换也是两个不同的动作。
分时操作系统VS实时操作系统分时操作系统是基于时间片的操作系统,时间片一结束,进程就会从CPU上剥离下来。
实时操作系统是一个进程运行完,才运行下一个进程,工业领域运行较多。
上图是Linux2.6内核中进程队列的数据结构。
⼀个CPU拥有⼀个runqueue
如果有多个CPU就要考虑进程个数的负载均衡问题
优先级
普通优先级:100〜139(我们都是普通的优先级,想想nice值的取值范围,可与之对应!)
实时优先级:0〜99(不关⼼)
活动队列
• 时间⽚还没有结束的所有进程都按照优先级放在该队列
• nr_active: 总共有多少个运⾏状态的进程
• queue[140]: ⼀个元素就是⼀个进程队列,相同优先级的进程按照FIFO规则进⾏排队调度,所以,数组下标就是优先级!
• 从该结构中,选择⼀个最合适的进程,过程是怎么的呢?
1. 从0下表开始遍历queue[140]
2. 找到第⼀个⾮空队列,该队列必定为优先级最⾼的队列
3. 拿到选中队列的第⼀个进程,开始运⾏,调度完成!
4. 遍历queue[140]时间复杂度是常数!但还是太低效了!
• bitmap[5]:⼀共140个优先级,⼀共140个进程队列,为了提⾼查找⾮空队列的效率,就可以⽤5*32个⽐特位表⽰队列是否为空,这样,便可以⼤ 提⾼查找效率!
过期队列
- 过期队列和活动队列结构⼀模⼀样
- 过期队列和活动队列结构一模一样
- 过期队列上放置的进程,都是时间⽚耗尽的进程
- 当活动队列上的进程都被处理完毕之后,对过期队列的进程进⾏时间⽚重新计算
active指针和expired指针
• active指针永远指向活动队列
• expired指针永远指向过期队列
• 可是活动队列上的进程会越来越少,过期队列上的进程会越来越多,因为进程时间⽚到期时⼀直都存在的。
• 没关系,在合适的时候,只要能够交换active指针和expired指针的内容,就相当于有具有了⼀批新的活动进程
为什么优先级既有PRI,又有NI?
如果在活跃队列里,把一个进程的优先级由80到60,我们是把该进程的位置调整吗?还是调整过期队列里的位置呢?这样做都不是很好,利用NI,活跃进程里的进程调度完之后,在过期队列里,根据NI,再重新调整该进程的位置。
总结
• 在系统当中查找⼀个最合适调度的进程的时间复杂度是⼀个常数,不随着进程增多⽽导致时间成本增加,我们称之为进程调度O(1)算法!

相关文章:
Linux中《进程状态--进程调度--进程切换》详细介绍
目录 进程状态Linux内核源代码怎么说运行&&阻塞&&挂起内核链表 进程状态查看Z(zombie)-僵尸进程僵尸进程危害孤儿进程 进程优先级进程切换Linux2.6内核进程O(1)调度队列 进程状态 Linux内核源代码怎么说 为了弄明白正在运⾏的进程是什么意思,我们…...
Element PlusAnt-design常问问题详解
Element UI Plus 高频面试问题解析(2025 版) 一、核心组件使用与原理 动态表头实现方案 • 场景:如何根据接口数据动态生成表头? • 技术方案: ◦ 使用 v-for 遍历表头数组生成 el-table-column ◦ 结合 render-header 属性实现复杂表头(如带提示的标题) ◦ 示例代码:通…...
【商城实战(96)】打造商城监控利器Prometheus与Grafana
【商城实战】专栏重磅来袭!这是一份专为开发者与电商从业者打造的超详细指南。从项目基础搭建,运用 uniapp、Element Plus、SpringBoot 搭建商城框架,到用户、商品、订单等核心模块开发,再到性能优化、安全加固、多端适配…...
Megatron-LM中的deepseek-v3实现
Megatron-LM:https://github.com/NVIDIA/Megatron-LM/tree/main 使用此仓库构建的著名的库也有很多,如: Colossal-AI, HuggingFace Accelerate, and NVIDIA NeMo Framework.Pai-Megatron-Patch工具是阿里人工智能平台PAI算法团队研发,ai-Megatron-Patch…...
SpringCloud如何整合DeepSeek
SpringCloud 整合 DeepSeek 的核心目标是通过微服务架构调用其分布式文件系统(如 3FS)或 API 服务。以下从技术选型、整合步骤和关键配置三个方面展开说明: 一、技术选型与架构分析 DeepSeek 服务类型 3FS 分布式文件系统:基于 RD…...
蓝桥杯备考:多米诺骨牌
这道题要求上下方格子和之差要最小,其实就是算每个上下格子的差求和的最小值 这道题其实是动态规划01背包问题 我们直接按步骤做吧 step1:定义状态表示f[i][j]表示从1到i个编号的差值里选出刚好j个数的最小操作次数 step2:推导状态转移方程 如图这就是我们的状态…...
wireshark开启对https密文抓包
HTTPS抓包解密指南 通常情况下,Wireshark只能抓取HTTP的明文包,对于HTTPS的报文需要特殊设置才能抓取。如果不进行设置,抓取到的都是TLS加密报文,这对调试工作造成了很大困难。 前言 提到HTTPS抓包,基本都绕不开SSL…...
AudioFlinger与AudioPoliceManager初始化流程
AF/APF启动流程 在启动AudioSeriver服务的过程中会对启动AF/APF。main_audioserver.cpp有如下代码: AudioFlinger::instantiate();AudioPolicyService::instantiate();AF初始化流程 1.AudioFlinger::instantiate() 1.1 AudioFlinger构造函数 void AudioFlinger:…...
网路传输层UDP/TCP
一、端口号 1.端口号 1.1 五元组 端口号(port)标识了一个主机上进行通信的不同的应用程序. 如图所示, 在一个机器上运行着许多进程, 每个进程使用的应用层协议都不一样, 比如FTP, SSH, SMTP, HTTP等. 当主机接收到一个报文中, 网络层一定封装了一个目的ip标识我这台主机, …...
Python大数据处理 基本的编程方法
目录 一、实验目的 二、实验要求 三、实验代码 四、实验结果 五、实验体会 一、实验目的 体会基本的python编程方法;学习python中的各类函数;了解python读取与写入文件的方法。 二、实验要求 输入2000年后的某年某月某日,判断这一天是…...
STM32F103_LL库+寄存器学习笔记06 - 梳理串口与串行发送“Hello,World“
导言 USART是嵌入式非常重要的通讯方式,它的功能强大、灵活性高且用途广泛。只停留在HAL库层面上用USART只能算是入门,要加深对USART的理解,必须从寄存器层面入手。接下来,先从最简单的USART串行发送开始。 另外,在接…...
硬件基础--14_电功率
电功率 电功率:指电流在单位时间内做的功(表示用电器消耗电能快慢的一个物理量)。 单位:瓦特(W),简称瓦。 公式:PUI(U为电压,单位为V,i为电流,单位为A,P为电功率,单位为W)。 单位换算:进位为1000ÿ…...
【C#语言】C#文件操作实战:动态路径处理与安全写入
文章目录 ⭐前言⭐一、场景痛点⭐二、完整实现代码⭐三、关键技术解析🌟1、动态路径处理🌟2、智能目录创建🌟3、安全的文件写入 ⭐四、进阶扩展方案🌟1、用户自定义路径选择🌟2、异常处理增强🌟3、异步写入…...
Vue.js 完全指南:从入门到精通
1. Vue.js 简介 1.1 什么是 Vue.js? Vue.js(通常简称为 Vue)是一个用于构建用户界面的渐进式 JavaScript 框架。所谓"渐进式",意味着 Vue 的设计是由浅入深的,你可以根据自己的需求选择使用它的一部分或全部功能。 Vue 最初由尤雨溪(Evan You)在 2014 年创…...
在Git仓库的Readme上增加目录页
一般在编写Readme时想要增加像文章那样的目录,方便快速跳转,但是Markdown语法并没有提供这样的方法,但是可以通过超链接结合锚点的方式来实现,如下图是我之前一个项目里写的Readme: 例如有下面几个Readme内容ÿ…...
C# SolidWorks 二次开发 -各种菜单命令增加方式
今天给大家讲一讲solidworks中各种菜单界面,如下图,大概有13处,也许还不完整哈。 1.CommandManager选项卡2.下拉选项卡3.菜单栏4.下级菜单5.浮动工具栏6.快捷方式工具栏7.FeatureManager工具栏区域8.MontionManager区域 ModelView?9.任务窗…...
分布式架构-Spring技术如何能实现分布式事务
在Spring技术栈中实现分布式事务,可通过多种成熟方案实现跨服务或跨数据库的事务一致性管理。以下是主要实现方式及技术要点: 一、基于Seata框架的AT模式 核心组件 TC (Transaction Coordinator):全局事务协调器(独立部署…...
【RocketMQRocketMQ Dashbord】Springboot整合RocketMQ
【RocketMQ&&RocketMQ Dashbord】Springboot整合RocketMQ 【一】Mac安装RocketMQ和RocketMQ Dashbord【1】安装RocketMQ(1)下载(2)修改 JVM 参数(3)启动测试(4)关闭测试&…...
vue 3 深度指南:从基础到全栈开发实践
目录 一、环境搭建与项目初始化 1. 前置依赖安装 2. 项目初始化与结构解析 二、核心概念与语法深度解析 1. MVVM 模式与响应式原理 2. 模板语法与指令进阶 3. 组件化开发 三、进阶开发与全栈集成 1. 路由管理(Vue Router) 2. 状态管理…...
《白帽子讲 Web 安全》之跨站请求伪造
引言 在数字化时代,网络已深度融入人们生活的方方面面,Web 应用如雨后春笋般蓬勃发展,为人们提供着便捷高效的服务。然而,繁荣的背后却潜藏着诸多安全隐患,跨站请求伪造(CSRF)便是其中极为隐蔽…...
K8S学习之基础五十:k8s中pod时区问题并通过kibana查看日志
k8s中pod默认时区不是中国的,挂载一个时区可以解决 vi pod.yaml apiVersion: v1 kind: Pod metadata:name: counter spec:containers:- name: countimage: 172.16.80.140/busybox/busybox:latestimagePullPolicy: IfNotPresentargs: [/bin/sh,-c,i0;while true;do …...
nginx代理前端请求
一,项目配置 我在 ip 为 192.168.31.177 的机器上使用 vue3 开发前端项目,项目中使用 axios 调用后端接口。 这是 axios 的配置: import axios from axios;const request axios.create({baseURL: http://192.168.31.177:8001,// 设置请求…...
LibVLC —— 《基于Qt的LibVLC专业开发技术》视频教程
🔔 LibVLC/VLC 相关技术、疑难杂症文章合集(掌握后可自封大侠 ⓿_⓿)(记得收藏,持续更新中…) 《基于Qt的LibVLC专业开发技术》课程视频,(CSDN课程主页、51CTO课程主页) 适合具有一些C++/Qt编程基础,想要进一步提高或涉足音视频行业的。本课程分7章节,共计35小节。…...
Android生态大变革,谷歌调整开源政策,核心开发不再公开
“开源”这个词曾经是Android的护城河,如今却成了谷歌的烫手山芋。最近谷歌宣布调整Android的开源政策,核心开发将全面转向私有分支。翻译成人话就是:以后Android的核心更新,不再公开共享了。 这操作不就是开源变节吗,…...
Android Gradle 插件问题:The option ‘android.useDeprecatedNdk‘ is deprecated.
问题与处理策略 问题描述 在 Android 项目中,报如下警告 The option android.useDeprecatedNdk is deprecated. The current default is false. It has been removed from the current version of the Android Gradle plugin. NdkCompile is no longer supported…...
【web应用安全】关于web应用安全的几个主要问题的思考
文章目录 防重放攻击1. **Token机制(一次性令牌)**2. **时间戳 超时验证**3. **Nonce(一次性随机数)**4. **请求签名(如HMAC)**5. **HTTPS 安全Cookie**6. **幂等性设计****综合防御策略建议****注意事项…...
Git 基础入门:从概念到实践的版本控制指南
一、Git 核心概念解析 1. 仓库(Repository) Git 的核心存储单元,包含项目所有文件及其完整历史记录。分为本地仓库(开发者本地副本)和远程仓库(如 GitHub、GitLab 等云端存储),支持…...
银行分布式新核心的部署架构(两地三中心)
银行的核心系统对可用性和性能要求均非常严苛,所以一般都采用两地三中心部署模式。 其中: 同城两个主数据中心各自部署一套热备,平时两个中心同时在线提供服务,进行负载均衡假如其中一个数据中心出现异常,则由另外一个…...
Spring 及 Spring Boot 条件化注解(15个)完整列表及示例
Spring 及 Spring Boot 条件化注解完整列表及示例 1. 所有条件化注解列表 Spring 和 Spring Boot 提供了以下条件化注解(共 15 个),用于在配置类或方法上实现条件化注册 Bean 或配置: 注解名称作用来源框架Conditional自定义条件…...
MantisBT在Windows10上安装部署详细步骤
MantisBT 是一款基于 Web 的开源缺陷跟踪系统,以下是在 Windows 10 上安装部署 MantisBT 的详细步骤: 1. 安装必要的环境 MantisBT 是一个基于 PHP 的 Web 应用程序,因此需要安装 Web 服务器(如 Apache)、PHP 和数据…...















