当前位置: 首页 > news >正文

从入门到精通:详解Linux进程管理

前言

在这篇文章中,我将带领大家深入学习和理解Linux系统中的进程管理。无论你是初学者还是有一定经验的开发者,相信这篇文章都会对你有所帮助。我们将详细讲解冯诺依曼体系结构、操作系统概念、进程管理、进程调度、进程状态、环境变量、内存管理以及其他相关内容。

冯诺依曼体系结构

概述

冯诺依曼体系结构是现代计算机系统的基础。它由数学家兼物理学家冯·诺依曼于1945年提出,至今仍被广泛应用于各种计算机系统中。冯诺依曼体系结构的核心思想是将程序和数据存储在同一存储器中,并由中央处理器(CPU)按顺序读取和执行指令。通过这种方式,计算机系统能够以更高效、更灵活的方式运行各种应用程序。

组成部分

冯诺依曼体系结构由以下几个主要部分组成:

  1. 输入单元:包括键盘、鼠标、扫描仪等设备,用于向计算机输入数据和指令。
  2. 中央处理器(CPU):包含运算器和控制器,用于执行指令和处理数据。运算器负责执行各种算术和逻辑运算,控制器负责指挥和协调各个部分的工作。
  3. 内存:用于存储程序和数据。内存分为随机存取存储器(RAM)和只读存储器(ROM),RAM用于存储正在运行的程序和数据,ROM用于存储固化的程序和数据。
  4. 输出单元:包括显示器、打印机等设备,用于输出计算结果和信息。

数据流动过程

在冯诺依曼体系结构中,所有数据的输入和输出都必须经过内存。具体来说,数据流动过程如下:

  1. 用户通过输入单元(如键盘)输入数据。
  2. 数据被存储在内存中。
  3. CPU从内存中读取指令和数据,并进行处理。
  4. 处理结果被写入内存。
  5. 输出单元(如显示器)从内存中读取结果并显示给用户。

这种数据流动方式确保了计算机系统的统一和高效。以QQ聊天为例,当你登录QQ并与好友聊天时,输入的信息首先被存储在内存中,CPU从内存中读取并处理这些信息,处理后的信息再次存储在内存中,最后通过显示器输出。若你发送文件,文件数据也会经过相同的路径流动,确保信息传递的可靠性。

操作系统(Operating System)

概念

操作系统(OS)是管理计算机硬件和软件资源的系统软件,负责为用户提供一个良好的操作环境。操作系统的核心部分是内核,它负责进程管理、内存管理、文件管理和驱动管理等。此外,操作系统还包括一些其他程序,如函数库和Shell程序。操作系统的功能可以概括为两个方面:资源管理和用户接口。

设计目的

操作系统的设计目的是:

  1. 与硬件交互:管理计算机的所有硬件资源,如CPU、内存、磁盘和输入输出设备。操作系统通过设备驱动程序与硬件进行交互,确保硬件设备能够被正确使用。
  2. 提供执行环境:为用户程序(应用程序)提供一个良好的执行环境,使用户能够方便地开发和运行应用程序。操作系统提供了丰富的系统调用和库函数,简化了应用程序的开发过程。

定位

在计算机软硬件架构中,操作系统的定位是一款“管理”软件。它通过描述和组织被管理对象,实现对系统资源的有效管理。例如,操作系统通过使用结构体(struct)描述硬件资源,通过链表或其他高效数据结构组织这些资源,从而实现对资源的管理。

系统调用和库函数

操作系统通过系统调用向上层开发者暴露部分接口,供其使用。系统调用提供了基本的功能,而库函数对系统调用进行了封装,提供了更高层次的接口,方便用户进行二次开发。例如,文件操作的系统调用包括openreadwrite等,而C标准库中的fopenfreadfwrite等函数则对这些系统调用进行了封装,使得文件操作更加方便和易于理解。

进程(Process)

基本概念

进程是程序的一个执行实例,代表正在运行的程序。进程是操作系统资源分配的基本单位,负责管理CPU时间、内存和其他资源。在内核中,进程被描述为一个分配系统资源的实体。每个进程都有自己独立的地址空间、堆栈以及文件描述符表。

描述进程—PCB

进程信息存储在一个叫做进程控制块(PCB)的数据结构中。PCB包含了进程的所有属性,是操作系统管理进程的核心数据结构。在Linux操作系统中,PCB被实现为task_struct结构体。

task_struct内容分类

task_struct包含以下内容:

  1. 标示符:描述进程的唯一标示符,用于区分其他进程。
  2. 状态:任务状态、退出代码、退出信号等。
  3. 优先级:相对于其他进程的优先级。
  4. 程序计数器:程序中即将被执行的下一条指令的地址。
  5. 内存指针:包括程序代码和进程相关数据的指针,以及与其他进程共享的内存块的指针。
  6. 上下文数据:进程执行时处理器寄存器中的数据。
  7. I/O状态信息:包括显示的I/O请求、分配给进程的I/O设备和被进程使用的文件列表。
  8. 记账信息:可能包括处理器时间总和、使用的时钟数总和、时间限制、记账号等。
  9. 其他信息:其他与进程相关的信息。

组织进程

在Linux内核中,所有运行的进程都以task_struct链表的形式存在内核中。通过这种方式,操作系统可以高效地管理和调度进程。每个task_struct结构体都包含指向下一个进程的指针,这样所有进程就形成了一个双向链表,操作系统可以方便地遍历和管理这些进程。

查看进程

用户可以通过/proc文件系统查看进程的信息。例如,要获取PID为1的进程信息,可以查看/proc/1文件夹。此外,用户还可以使用topps等命令行工具获取进程信息。ps命令可以显示系统中所有正在运行的进程及其详细信息,而top命令则可以动态地显示系统资源的使用情况和进程状态。

示例代码

以下示例代码展示了如何使用ps命令查看系统中所有进程的信息:

ps -aux

该命令输出的信息包括进程ID、用户ID、CPU使用率、内存使用率、进程状态、命令名称等。

进程状态

进程的不同状态

在Linux内核中,进程可以处于以下几种状态:

  1. R(运行状态):表明进程正在运行或在运行队列中等待运行。
  2. S(睡眠状态):表明进程在等待事件完成,有时也称为可中断睡眠(interruptible sleep)。
  3. D(磁盘休眠状态):有时也称为不可中断睡眠状态(uninterruptible sleep),通常等待I/O操作完成。
  4. T(停止状态):进程被停止,可以通过发送SIGSTOP信号暂停进程,通过SIGCONT信号恢复运行。
  5. X(死亡状态):进程已经终止,不会出现在任务列表中。
  6. Z(僵尸状态):进程已经终止,但其退出状态还没有被父进程读取,保持在进程表中。

查看进程状态

用户可以通过pstop等命令查看进程状态。例如,使用ps aux命令可以查看系统中所有进程及其状态。以下是ps aux命令的示例输出:

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.1  22568  1196 ?        Ss   10:00   0:01 /sbin/init
root       672  0.00.3  37644  3312 ?        Ss   10:00   0:02 /usr/sbin/sshd

在输出信息中,STAT字段表示进程的状态。例如,Ss表示进程处于睡眠状态且是会话领导进程,R表示进程正在运行。

示例代码

以下示例代码展示了如何使用top命令动态查看系统资源使用情况和进程状态:

top

top命令界面中,用户可以看到系统的总体资源使用情况,包括CPU、内存和交换分区的使用率,以及所有正在运行的进程的信息。用户可以通过按k键终止进程,通过按r键调整进程的优先级。

僵尸进程(Zombie Process)

概念与形成原因

僵尸进程是已经终止但其退出状态尚未被父进程读取的进程。当子进程退出后,父进程需要通过waitwaitpid系统调用读取子进程的退出状态,否则子进程会保持在僵尸状态。僵尸进程的出现是由于父进程没有及时回收子进程的资源,导致子进程的信息无法从系统中清除。

危害

僵尸进程会占用系统资源,特别是进程控制块(PCB)中的内存资源。如果大量僵尸进程存在,会导致系统资源枯竭,影响系统性能和稳定性。此外,僵尸进程的存在还可能影响系统的正常运行和维护,因为系统管理员可能会误以为这些进程仍在运行。

解决方法

通过在父进程中使用waitwaitpid函数可以避免僵尸进程。例如,父进程可以在子进程终止时调用wait函数读取子进程的退出状态,从而释放其占用的资源。以下是一个示例代码,展示了如何在父进程中使用wait函数回收子进程的资源:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>int main() {pid_t pid = fork();if (pid < 0) {perror("fork");return 1;} else if (pid == 0) {printf("Child process\n");sleep(2);exit(0);} else {printf("Parent process\n");wait(NULL);  // 回收子进程资源printf("Child process terminated\n");}return 0;
}

在这个示例中,父进程通过调用wait函数等待子进程终止,并回收其资源,避免了僵尸进程的产生。

孤儿进程(Orphan Process)

概念与形成原因

孤儿进程是其父进程已经终止,但子进程仍在运行的进程。孤儿进程会被系统的1号进程(init进程)收养,并由init进程负责回收资源。孤儿进程的产生通常是由于父进程异常终止或故意终止,而子进程仍需要继续执行其任务。

危害与处理

孤儿进程不会对系统造成危害,因为它们会被init进程收养并管理。操作系统通过这种机制确保所有进程都能被正确管理和回收。以下是一个示例代码,展示了孤儿进程的形成过程:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>int main() {pid_t pid = fork();if (pid < 0) {perror("fork");return 1;} else if (pid == 0) {// 子进程sleep(5);  // 保证子进程在父进程退出后继续运行printf("Child process: parent PID = %d\n", getppid());exit(0);} else {// 父进程printf("Parent process\n");exit(0);  // 父进程立即退出}return 0;
}

在这个示例中,父进程立即退出,子进程在父进程退出后继续运行,此时子进程成为孤儿进程,并被init进程收养。通过在子进程中打印父进程的PID,可以验证子进程在成为孤儿进程后,其父进程PID会变为1(init进程的PID)。

进程优先级

基本概念

进程优先级决定了进程获得CPU时间的先后顺序。优先级高的进程优先获得CPU资源,从而更快地执行。Linux系统中,用户可以通过调整进程的nice值来改变进程的优先级。nice值的范围为-20到19,值越小优先级越高。

查看进程优先级

用户可以使用ps -l命令查看进程的优先级和nice值。例如:

ps -l

输出信息中包含以下重要字段:

  • UID:执行者的身份。
  • PID:进程ID。
  • PPID:父进程ID。
  • PRI:进程的优先级,值越小优先级越高。
  • NI:进程的nice值。

调整进程优先级

用户可以使用nice命令启动一个具有特定优先级的进程,也可以使用renice命令调整已有进程的优先级。例如:

nice -n 10 ./myprogram
renice -n -5 -p 12345

以下是一个示例代码,展示了如何使用nice命令启动一个具有特定优先级的进程:

nice -n -10 ./myprogram

在这个示例中,myprogram程序将以较高的优先级运行,因为其nice值被设置为-10。

示例代码

以下是一个完整的示例代码,展示了如何调整进程的优先级并查看其效果:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>int main() {pid_t pid = fork();if (pid < 0) {perror("fork");return 1;} else if (pid == 0) {// 子进程int ret = nice(-10);  // 设置较高优先级if (ret == -1) {perror("nice");}printf("Child process: nice value = %d\n", ret);while (1) {// 子进程持续运行,观察优先级的影响}} else {// 父进程printf("Parent process\n");while (1) {// 父进程持续运行,观察优先级的影响}}return 0;
}

运行该程序后,可以使用ps -l命令查看子进程和父进程的优先级和nice值,并观察其在系统中的表现。

环境变量

基本概念

环境变量是操作系统中用来指定操作系统运行环境的一些参数。在编写C/C++代码时,编译器可以通过环境变量查找所需的动态或静态库。环境变量通常具有全局特性,可以影响系统中的所有进程。

常见环境变量

  • PATH:指定命令的搜索路径。当用户在终端中输入命令时,系统会在PATH指定的目录中搜索可执行文件。
  • HOME:指定用户的主工作目录,即用户登录到系统后的默认目录。
  • SHELL:指定当前Shell的路径,通常是/bin/bash

查看和设置环境变量

用户可以使用以下命令查看和设置环境变量:

echo $PATH  # 查看PATH环境变量
export MYVAR="Hello, World!"  # 设置环境变量
unset MYVAR  # 清除环境变量
env  # 显示所有环境变量

示例代码

以下是一个示例代码,展示了如何在程序中获取和设置环境变量:

#include <stdio.h>
#include <stdlib.h>int main() {char *path = getenv("PATH");if (path) {printf("PATH: %s\n", path);}setenv("MYVAR", "Hello, World!", 1);printf("MYVAR: %s\n", getenv("MYVAR"));return 0;
}

在这个示例中,程序首先获取并打印PATH环境变量的值,然后设置一个新的环境变量MYVAR并打印其值。

环境变量的全局属性

环境变量通常具有全局属性,可以被子进程继承。例如,通过export命令设置的环境变量可以在子进程

中访问:

export MYVAR="Hello, World!"
./myprogram

子进程运行时可以访问并打印MYVAR的值。

示例代码

以下是一个示例代码,展示了环境变量的全局属性:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>int main() {pid_t pid = fork();if (pid < 0) {perror("fork");return 1;} else if (pid == 0) {// 子进程printf("Child process: MYVAR = %s\n", getenv("MYVAR"));} else {// 父进程printf("Parent process\n");setenv("MYVAR", "Hello from parent", 1);wait(NULL);  // 等待子进程终止}return 0;
}

在这个示例中,父进程设置了一个环境变量MYVAR,子进程继承并打印了该环境变量的值。

进程地址空间

基本概念

进程地址空间是操作系统为每个进程分配的虚拟内存空间。在32位系统中,进程地址空间通常为4GB。地址空间分为用户空间和内核空间,用户空间用于存放用户程序和数据,内核空间用于存放操作系统内核和内核数据。

虚拟地址与物理地址

虚拟地址是用户程序看到的地址,而物理地址是内存中的实际地址。操作系统通过页表将虚拟地址映射到物理地址,确保程序在运行时能够正确访问内存。

进程地址空间布局

进程地址空间通常包含以下几部分:

  1. 代码段:存放程序代码。
  2. 数据段:存放全局变量和静态变量。
  3. :用于动态内存分配。
  4. :用于函数调用时存放局部变量和返回地址。

示例代码

以下是一个简单的示例,展示了进程地址空间的使用:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>int global_var = 0;int main() {pid_t pid = fork();if (pid < 0) {perror("fork");return 1;} else if (pid == 0) {  // 子进程global_var = 100;printf("Child: %d, %p\n", global_var, &global_var);} else {  // 父进程sleep(1);printf("Parent: %d, %p\n", global_var, &global_var);}return 0;
}

运行该程序会显示父子进程中变量地址相同但值不同的现象,说明虚拟地址相同但物理地址不同。通过这个示例,可以理解虚拟地址和物理地址的区别,以及进程地址空间的布局。

进程调度

调度算法

Linux内核使用多种调度算法来管理进程的执行顺序。常见的调度算法包括先来先服务(FCFS)、最短作业优先(SJF)、优先级调度(Priority Scheduling)和时间片轮转(Round Robin)。这些算法各有优缺点,适用于不同的场景和需求。

O(1)调度算法

Linux 2.6内核采用了O(1)调度算法,该算法确保调度操作的时间复杂度为常数,不随进程数量增加而增加。O(1)调度算法使用两个队列来管理进程:活动队列和过期队列。活动队列存放正在运行或准备运行的进程,过期队列存放时间片已耗尽的进程。

活动队列与过期队列

  • 活动队列:存放正在运行或准备运行的进程。调度器从活动队列中选择优先级最高的进程进行调度。
  • 过期队列:存放时间片已耗尽的进程。当活动队列中的进程全部运行完毕后,调度器会将活动队列和过期队列交换,重新开始调度。

示例代码

以下是一个示例代码,展示了如何在Linux内核中实现进程调度:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>int main() {pid_t pid1, pid2;pid1 = fork();if (pid1 == 0) {// 子进程1while (1) {printf("Child 1 running\n");sleep(1);}} else {pid2 = fork();if (pid2 == 0) {// 子进程2while (1) {printf("Child 2 running\n");sleep(1);}} else {// 父进程while (1) {printf("Parent running\n");sleep(1);}}}return 0;
}

运行该程序后,可以观察到父进程和两个子进程轮流执行,展示了时间片轮转调度的效果。

环境变量的组织方式

环境表

每个程序都会收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以\0结尾的环境字符串。

获取和设置环境变量

用户可以通过系统调用或库函数获取和设置环境变量。例如,使用getenvsetenv函数可以访问特定的环境变量:

#include <stdio.h>
#include <stdlib.h>int main() {char *path = getenv("PATH");if (path) {printf("PATH: %s\n", path);}setenv("MYVAR", "Hello, World!", 1);printf("MYVAR: %s\n", getenv("MYVAR"));return 0;
}

在这个示例中,程序首先获取并打印PATH环境变量的值,然后设置一个新的环境变量MYVAR并打印其值。

环境变量的全局属性

环境变量通常具有全局属性,可以被子进程继承。例如,通过export命令设置的环境变量可以在子进程中访问:

export MYVAR="Hello, World!"
./myprogram

子进程运行时可以访问并打印MYVAR的值。

示例代码

以下是一个示例代码,展示了环境变量的全局属性:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>int main() {pid_t pid = fork();if (pid < 0) {perror("fork");return 1;} else if (pid == 0) {// 子进程printf("Child process: MYVAR = %s\n", getenv("MYVAR"));} else {// 父进程printf("Parent process\n");setenv("MYVAR", "Hello from parent", 1);wait(NULL);  // 等待子进程终止}return 0;
}

在这个示例中,父进程设置了一个环境变量MYVAR,子进程继承并打印了该环境变量的值。

进程内存映像

程序地址空间回顾

程序地址空间通常包含代码段、数据段、堆和栈。在32位系统中,地址空间分为用户空间和内核空间。用户空间用于存放用户程序和数据,内核空间用于存放操作系统内核和内核数据。

虚拟地址与物理地址

虚拟地址是用户程序看到的地址,而物理地址是内存中的实际地址。操作系统通过页表将虚拟地址映射到物理地址,确保程序在运行时能够正确访问内存。

进程地址空间布局

进程地址空间通常包含以下几部分:

  1. 代码段:存放程序代码。
  2. 数据段:存放全局变量和静态变量。
  3. :用于动态内存分配。
  4. :用于函数调用时存放局部变量和返回地址。

示例代码

以下是一个简单的示例,展示了进程地址空间的使用:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>int global_var = 0;int main() {pid_t pid = fork();if (pid < 0) {perror("fork");return 1;} else if (pid == 0) {  // 子进程global_var = 100;printf("Child: %d, %p\n", global_var, &global_var);} else {  // 父进程sleep(1);printf("Parent: %d, %p\n", global_var, &global_var);}return 0;
}

运行该程序会显示父子进程中变量地址

相同但值不同的现象,说明虚拟地址相同但物理地址不同。通过这个示例,可以理解虚拟地址和物理地址的区别,以及进程地址空间的布局。

总结

通过本文的学习,我们详细介绍了Linux系统中的进程管理。从冯诺依曼体系结构、操作系统概念、进程管理、进程调度、进程状态、环境变量、内存管理等多个方面进行了深入讲解。掌握这些知识,可以帮助我们更高效地管理和使用Linux系统。希望这篇文章对大家有所帮助。如果有任何问题或建议,欢迎在评论区留言与我交流。感谢大家的阅读!

相关文章:

从入门到精通:详解Linux进程管理

前言 在这篇文章中&#xff0c;我将带领大家深入学习和理解Linux系统中的进程管理。无论你是初学者还是有一定经验的开发者&#xff0c;相信这篇文章都会对你有所帮助。我们将详细讲解冯诺依曼体系结构、操作系统概念、进程管理、进程调度、进程状态、环境变量、内存管理以及其…...

【Linux】如何在 Linux 系统中使用 envsubst 来处理 Nginx 配置模板

一、创建 nginx.template 模板文件 vim nginx.template复制下面文件内容 server { listen ${BY_PORT}; server_name ${BY_HOST}; location /sys/ { proxy_pass http://${BY_GRAFANA_HOST}:${BY_GRAFANA_PORT}/; } # 其他配置... }这个模板中包含了几个环境变量&#…...

【LeetCode】438.找到字符串中所有字母异位词

找到字符串中所有字母异位词 题目描述&#xff1a; 给定两个字符串 s 和 p&#xff0c;找到 s 中所有 p 的 异位词 的子串&#xff0c;返回这些子串的起始索引。不考虑答案输出的顺序。 异位词 指由相同字母重排列形成的字符串&#xff08;包括相同的字符串&#xff09;。 示…...

力扣96. 不同的二叉搜索树

Problem: 96. 不同的二叉搜索树 文章目录 题目描述思路复杂度Code 题目描述 思路 一个数字做根节点的话可能的结果为&#xff1a;其左边数字做子树的组合数字乘以其右边数字做子树的个数之积 1.创建备忘录memo&#xff1b; 2.递归分别求取当前数字左边和右边数字做子树的数量&…...

哈希表的用途

...

k8s笔记 | 高度调度

CronJob计划任务 简介&#xff1a;在k8s中周期性运行计划任务&#xff0c;与linux中的crontab相同&#xff1b;注意点 CornJob执行的时间是controller-manager的时间&#xff0c;所以一定要确保controller-manager的时间是准确的&#xff0c;另外cornjob cron表达式 文章参…...

Rom应用开发遇到得一些小bug

记录一些细碎得bug ROM时间类问题 问题描述&#xff1a; 设备拔电重启&#xff0c;ROM时间为默认时间如1970年1月1日&#xff0c;与某些业务场景互斥 问题原因&#xff1a; 后台接口校验https证书校验失败&#xff0c;要求是2年内得请求头校验了时间戳&#xff0c;时间戳过期…...

Python简介

Python简介 1. Python定义 Python 是一种简单易学并且结合了解释性、编译性、互动性和面向对象的脚本语言。Python提供了高级数据结构&#xff0c;它的语法和动态类型以及解释性使它成为广大开发者的首选编程语言。 Python 是解释型语言&#xff1a; 开发过程中没有了编译这个环…...

C++完成特色旅游管理信息系统

背景&#xff1a; 继C完成淄博烧烤节管理系统后&#xff0c;我们来到了特色旅游管理信息系统的代码编写&#xff0c;历史链接点下方。 C完成淄博烧烤节管理系统_淄博烧烤总账管理系统的-CSDN博客 问题描述&#xff1a; 为了更好的管理各个服务小组&#xff0c;开发相应的管…...

贵州大学24计算机考研数据速览,国家重点实验室22408复试线285分!贵州大学计算机考研考情分析!

贵州大学计算机科学与技术学院坐落在贵州大学北校区&#xff08;贵阳花溪&#xff09;。 学院现有教职工139人&#xff0c;其中专职教师126人&#xff0c;教授17人&#xff0c;副教授37人&#xff0c;讲师46人&#xff0c;高级实验师4人&#xff0c;实验师17人。具有博士学位的…...

分区4K对齐那些事,你想知道的都在这里

在对磁盘进行分区时,有一个很重要的注意事项,就是要将分区对齐,不对齐可能会造成磁盘性能的下降。尤其是固态硬盘SSD,基本上都要求4K对齐。磁盘读写速度慢还找不到原因?可能就是4K对齐的锅。那么分区对齐究竟是怎么回事?为什么要对齐?如何才能对齐?如何检测是否对齐呢?…...

达梦数据库学习笔记

架构、特点和基本概念 达梦数据库&#xff08;DM Database&#xff09;是中国达梦数据库有限公司自主研发的关系型数据库管理系统。它广泛应用于政府、金融、电信、能源等行业&#xff0c;具备高性能、高可靠性和高安全性的特点。 架构 达梦数据库的架构设计注重高性能和高可…...

安卓绕过限制直接使用Android/data无需授权,支持安卓14(部分)

大家都知道&#xff0c;安卓每次更新都会给权限划分的更细、收的更紧。   早在安卓11的时候还可以直接通过授权Android/data来实现操作其他软件的目录&#xff0c;没有之前安卓11授权的图了&#xff0c;反正都长一个样&#xff0c;就直接贴新图了。   后面到了安卓12~13的…...

【知识蒸馏】多任务模型 logit-based 知识蒸馏实战

一、什么是逻辑&#xff08;logit&#xff09;知识蒸馏 Feature-based蒸馏原理是知识蒸馏中的一种重要方法&#xff0c;其关键在于利用教师模型的隐藏层特征来指导学生模型的学习过程。这种蒸馏方式旨在使学生模型能够学习到教师模型在特征提取和表示方面的能力&#xff0c;从…...

C:技术面试总结

1 变量的声明和定义: 定义:为变量分配地址和存储空间 声明:不分配地址。一个变量可以在多个地方声明,但只能在一个地方定义。extern修饰的变量声明,说明此变量将在文件以外或文件后面部分定义。 2 局部变量是否能与全局变量重名: 可以,局部变量会屏蔽全局变量 局部…...

OpenHarmony 实战开发——一文总结ACE代码框架

一、前言 ACE_Engine框架是OpenAtom OpenHarmony&#xff08;简称“OpenHarmony”&#xff09;的UI开发框架&#xff0c;为开发者提供在进行应用UI开发时所必需的各种组件&#xff0c;以及定义这些组件的属性、样式、事件及方法&#xff0c;通过这些组件可以方便进行OpenHarmo…...

【数据结构与算法】之堆的应用——堆排序及Top_K问题!

目录 1、堆排序 2、Top_K问题 3、完结散花 个人主页&#xff1a;秋风起&#xff0c;再归来~ 数据结构与算法 个人格言&#xff1a;悟已往之不谏&#xff0c;知来者犹可追 克心守己&#xff0c;律己则安&#xff01; 1、堆排序 对一个无序的数组…...

啊哈!算法-第2章-栈、队列、链表

啊哈!算法-第2章-栈、队列、链表 第1节 解密qq号——队列第2节 解密回文——栈第3节 纸牌游戏——小猫钓鱼第4节 链表第5节 模拟链表 第1节 解密qq号——队列 新学期开始了&#xff0c;小哈是小哼的新同桌(小哈是个大帅哥哦~)&#xff0c;小哼向小哈询问 QQ 号&#xff0c; 小…...

简述 v-if 和 v-show 的区别

v-if 和 v-show 都是 Vue.js 中用于控制元素显示与隐藏的指令&#xff0c;但它们的工作方式有显著的差异。以下是它们之间的主要区别&#xff1a; 渲染方式&#xff1a; v-if&#xff1a;v-if 是“真正”的条件渲染&#xff0c;因为它会确保在切换过程中条件块内的事件监听器和…...

Linux驱动学习之模块化,参数传递,符号导出

1.模块化 1.1.模块化的基本概念&#xff1a; 模块化是指将特定的功能或组件独立出来&#xff0c;以便于开发、测试和维护。在Linux设备驱动中&#xff0c;模块化允许将驱动程序作为内核模块动态加载到系统中&#xff0c;从而提高了系统的灵活性和可扩展性。 1.2.Linux内核模…...

RabbitMQ02-RebbitMQ简介及交换器

一. AMQP协议 什么是AMQP协议 AMQP(Advanced Message Queuing Protocol,高级消息队列协议):它是进程之间传递异步消息的网络协议 AMQP工作过程 发布者通过发布消息&#xff0c;通过交换机&#xff0c;交换机根据路由规则将收到的消息分发交换机绑定的下消息队列&#xff0c;最…...

Matlab自学笔记三十:元胞数组的修改、添加、删除和连接

1.说明 元胞数组的子数组或元素也是元胞型的&#xff0c;其元素内容&#xff08;值&#xff09;是本身类型&#xff0c;因此&#xff0c;在添、删、改和连接处理时&#xff0c;必须明确每个元素的值的类型和大小&#xff0c;否则&#xff0c;编程报错是不可避免的了。看本文前…...

【LeetCode】数组——双指针法

1 双指针法 1.1 介绍 双指针法是一种常用的算法技巧&#xff0c;通常用于处理数组或链表中的问题。它使用两个指针&#xff0c;通常一个从数组的开始位置遍历&#xff0c;另一个从数组的末尾位置开始遍历&#xff0c;根据问题的不同&#xff0c;这两个指针可以同时移动&#…...

react 低代码平台方案汇总

React作为当前最流行的前端框架之一&#xff0c;其生态系统中孕育了多种低代码平台方案&#xff0c;旨在加速应用开发过程。以下是几款基于React的低代码平台或工具&#xff0c;它们通过可视化构建、预制组件、数据绑定等功能&#xff0c;帮助开发者快速构建应用程序&#xff1…...

oss对象上传文件设置格式

PostMapping("upload")ApiOperation(value "上传文件")public Result<UploadDTO> upload(RequestParam("file") MultipartFile file) throws Exception {if (file.isEmpty()) {return new Result<UploadDTO>().error(ModuleErrorCo…...

【Linux学习】进程

下面是有关进程的相关介绍&#xff0c;希望对你有所帮助&#xff01; 小海编程心语录-CSDN博客 目录 1. 进程的概念 1.1 进程与程序 1.2 进程号 2. 进程的状态 2.1 fork创建子进程 2.2 父子进程间的文件共享 3. 进程的诞生与终止 3.1 进程的诞生 3.2 进程的终止 1. 进…...

Python数据分析实验四:数据分析综合应用开发

目录 一、实验目的与要求二、主要实验过程1、加载数据集2、数据预处理3、划分数据集4、创建模型估计器5、模型拟合6、模型性能评估 三、主要程序清单和运行结果四、实验体会 一、实验目的与要求 1、目的&#xff1a; 综合运用所学知识&#xff0c;选取有实际背景的应用问题进行…...

基于51单片机的盆栽自动浇花系统

一.硬件方案 工作原理是湿度传感器将采集到的数据直接传送到ADC0832的IN端作为输入的模拟信号。选用湿度传感器和AD转换&#xff0c;电路内部包含有湿度采集、AD转换、单片机译码显示等功能。单片机需要采集数据时&#xff0c;发出指令启动A/D转换器工作&#xff0c;ADC0832根…...

SpirngMVC框架学习笔记(一):SpringMVC基本介绍

1 SpringMVC 特点&概述 SpringMVC 从易用性&#xff0c;效率上 比曾经流行的 Struts2 更好 SpringMVC 是 WEB 层框架&#xff0c;接管了 Web 层组件, 比如控制器, 视图, 视图解析, 返回给用户的数据格式, 同时支持 MVC 的开发模式/开发架构SpringMVC 通过注解&#xff0c;…...

实现信号发生控制

1. 信号发生器的基本原理 信号发生器是一种能够产生特定波形和频率的电子设备&#xff0c;常用于模拟信号的产生和测试。 信号发生器的基本原理 信号发生器的工作原理基于不同的技术&#xff0c;但最常见的类型包括模拟信号发生器和数字信号发生器&#xff08;DDS&#xff0…...