嵌入式知识点总结 Linux驱动 (五)-linux内核

针对于嵌入式软件杂乱的知识点总结起来,提供给读者学习复习对下述内容的强化。

目录

1.内核镜像格式有几种?分别有什么区别?

2.内核中申请内存有哪几个函数?有什么区别?

3.什么是内核空间,用户空间?

4.为什么需要区分内核空间与用户空间?

5.什么是内核态和用户态?

6.用户空间与内核通信方式有哪些?

7.内核链表为什么具有通用性?

8.应用程序中open()在linux中执行过程中是如何从用户空间到内核空间?

9.怎么申请大块内核内存?


1.内核镜像格式有几种?分别有什么区别?

1. zImage

描述

zImage 是一种压缩的内核镜像格式,适用于大多数嵌入式系统和x86架构。

它是通过将内核镜像压缩后,加上解压缩代码生成的。

特点

压缩格式,体积较小。

适用于内存有限的嵌入式系统。

通常用于传统的BIOS引导方式。

适用场景

嵌入式Linux系统。

旧版x86系统。

2. bzImage

描述

bzImage 是 zImage 的升级版,主要用于x86架构。

名称中的 b 代表 "big",表示它支持更大的内核镜像。

特点

支持更大的内核镜像(超过512KB)。

压缩格式,体积较小。

适用于现代x86系统(如UEFI引导)。

适用场景

现代x86架构的Linux系统。

3. uImage

描述

uImage 是U-Boot引导加载程序专用的内核镜像格式。

它在 zImage 或 bzImage 的基础上添加了一个U-Boot头部,包含加载地址、入口地址等信息。

特点

专为U-Boot设计。

包含额外的元数据,便于U-Boot加载和引导。

适用场景

使用U-Boot引导的嵌入式系统(如ARM架构)。

4. Image

描述

Image 是未经压缩的内核镜像格式。

它是内核编译后直接生成的原始二进制文件。

特点

未压缩,体积较大。

加载速度快(无需解压缩)。

适用场景

内存充足且对启动速度要求较高的系统。

5. FIT Image(Flattened Image Tree)

描述

FIT Image 是一种灵活的镜像格式,支持将内核、设备树、RAM磁盘等多个组件打包到一个镜像中。

它基于设备树(Device Tree)的概念,适用于复杂的嵌入式系统。

特点

支持多组件打包。

灵活性高,适合复杂的引导需求。

适用场景

现代嵌入式系统(如ARM架构)。

需要同时加载内核、设备树和初始RAM磁盘的系统。

6. vmlinux

描述

vmlinux 是内核编译后生成的ELF(Executable and Linkable Format)文件。

它是未经压缩和处理的原始内核镜像。

特点

未压缩,体积最大。

包含调试信息,适合调试和分析。

适用场景

内核开发和调试。

7. vmlinuz

描述

vmlinuz 是 vmlinux 的压缩版本,通常用于x86架构的Linux发行版。

它是 zImage 或 bzImage 的另一种形式。

特点

压缩格式,体积较小。

适用于x86架构的Linux系统。

适用场景

桌面和服务器Linux系统。

8. XIP Kernel(Execute In Place)

描述

XIP Kernel 是一种可以直接在存储设备上执行的内核镜像格式。

它不需要将内核加载到内存中,直接从存储设备(如NOR Flash)执行。

特点

节省内存空间。

执行速度较慢(受存储设备速度限制)。

适用场景

内存非常有限的嵌入式系统。

嵌入式Linux中常用的镜像格式

在嵌入式Linux开发中,最常见的镜像格式是 uImage 和 FIT Image,因为它们专为嵌入式系统设计,支持U-Boot引导加载程序,并且可以灵活地处理内核、设备树和初始RAM磁盘。

uImage 示例

# 使用 mkimage 工具生成 uImage
mkimage -A arm -T kernel -C none -a 0x80008000 -e 0x80008000 -n "Linux Kernel" -d zImage uImage

FIT Image 示例

# 使用 mkimage 工具生成 FIT Image
mkimage -f kernel.its kernel.itb

2.内核中申请内存有哪几个函数?有什么区别?

1. kmalloc()

作用:用于分配小块内存(通常小于 4 KB,一般用于 SLAB/SLUB 分配器)。

返回值:返回一个指向物理连续内存的指针。

优点

速度快,适用于小块内存分配。

分配的内存是物理连续的,适用于 DMA 等场景。

缺点

不能保证分配大块内存(超过单个页面时,可能失败)

void *ptr = kmalloc(1024, GFP_KERNEL); // 分配 1024 字节内存
if (!ptr) printk("kmalloc failed!\n");

2. kzalloc()

作用:类似 kmalloc(),但会自动清零分配的内存(等价于 kmalloc() + memset(0))。

void *ptr = kzalloc(1024, GFP_KERNEL);

3. vmalloc()

作用:用于分配大块内存(超过单个页面),但是分配的内存是虚拟地址连续的,物理地址不一定连续。

适用于

需要大块内存但不需要物理连续性的场景,如驱动的缓冲区。

缺点

由于页表映射,访问速度比 kmalloc() 分配的内存慢。

不能用于 DMA(因为物理地址不连续)

void *ptr = vmalloc(1024 * 1024); // 分配 1MB 内存

4. vzalloc()

作用:类似 vmalloc(),但会自动清零分配的内存。

void *ptr = vzalloc(1024 * 1024);
函数物理连续虚拟地址连续适用场景
kmalloc()小块内存,物理连续,可用于 DMA
kzalloc()kmalloc() + 清零
vmalloc()大块内存,物理不连续,不能用于 DMA
vzalloc()vmalloc() + 清零
alloc_pages()以页为单位分配,适用于页级管理
get_free_pages()类似 alloc_pages(),但返回虚拟地址
dma_alloc_coherent()专用于 DMA,返回设备可访问的地址

ioremap() 在内核中的作用

在 Linux 内核驱动开发中,ioremap() 主要用于将物理地址映射到内核的虚拟地址空间,使 CPU 可以访问设备寄存器外部存储器

ioremap() 相关函数

函数作用适用场景
ioremap()将物理地址映射为不可缓存的虚拟地址访问 MMIO(内存映射 I/O),如外设寄存器
ioremap_nocache()ioremap() 的别名,确保不使用 CPU 缓存旧版 API,现已废弃,等同于 ioremap()
ioremap_wc()写合并(Write Combining),提高写入速度适用于帧缓冲等高速写操作
ioremap_cache()允许使用 CPU 缓存适用于 RAM 访问,提高访问效率
iounmap()解除 ioremap() 映射释放内存映射资源

3.什么是内核空间,用户空间?

4.为什么需要区分内核空间与用户空间?

在 CPU 的所有指令中,,有些指令是非常危险的,如果错用,将导致系统崩溃,比如清内存、设置时钟等。如果允许所有的程序都可以使用这些指令,那么系统崩溃的概率将大大增加。
所以,CPU 将指令分为特权指令和非特权指令,对于那些危险的指令,只允许操作系统及其相关模块使用,普通应用程序只能使用那些不会造成灾难的指令。比如 Intel 的 CPU 将特权等级分为4个级别:Ring0~Ring3.
其实 Linux 系统只使用了 Ring0 和 Ring3 两个运行级别(Windows 系统也是一样的)。当进程运行在Ring3 级别时被称为运行在用户态,而运行在 Ring0 级别时被称为运行在内核态。

5.什么是内核态和用户态?

当进程运行在内核空间时就处于内核态,而进程运行在用户空间时则处于用户态。
在内核态下,进程运行在内核地址空间中,此时CPU可以执行任何指令。运行的代码也不受任何的限制,可以自由地访问任何有效地址,也可以直接进行端口的访问。
在用户态下,进程运行在用户地址空间中,被执行的代码要受到 CPU 的诸多检查,它们只能访问映射其地址空间的页表项中规定的在用户态下可访问页面的虚拟地址,且只能对任务状态段(TSS)中 I/0 许可位图(IO Permission Bitmap)中规定的可访问端口进行直接访问。
对于以前的 DOS 操作系统来说,是没有内核空间、用户空间以及内核态、用户态这些概念的。可以认为所有的代码都是运行在内核态的,因而,用户编写的应用程序代码可以很容易的让操作系统崩溃掉。
对于 Linux 来说,通过区分内核空间和用户空间的设计,隔离了操作系统代码(操作系统的代码要比应用程序的代码健壮很多)与应用程序代码。即便是单个应用程序出现错误,也不会影响到操作系统的稳定性,这样其它的程序还可以正常的运行(Linux 可是个多任务系统啊!)。所以,区分内核空间和用户空间本质上是要提高操作系统的稳定性及可用性。

在 Linux 及其他现代操作系统中,内核态(Kernel Mode)用户态(User Mode) 是 CPU 运行的两种模式,主要用于隔离用户进程和操作系统核心代码,确保系统稳定性和安全性。

特性内核态(Kernel Mode)用户态(User Mode)
权限级别高(Ring 0)低(Ring 3)
可访问资源访问所有 CPU 指令和硬件资源只能访问进程自己的虚拟地址空间
内存访问访问整个物理内存只能访问自身进程的虚拟内存
I/O 访问允许直接访问 I/O 设备不能直接访问 I/O 设备
CPU 指令可执行特权指令(如 clisti只能执行非特权指令
切换方式通过 系统调用(syscall) 进入通过 系统调用返回sigreturn 退出

6.用户空间与内核通信方式有哪些?

1. 系统调用(System Call)

原理:

用户空间调用 glibc 提供的 API(如 open()read()),最终进入内核态执行对应的 sys_xxx() 函数。

通过 syscall 指令(x86_64)或 int 0x80(x86)切换到内核态。

适用场景:

文件操作(open()read()write()

进程管理(fork()execve()

设备驱动访问(ioctl()

#include <stdio.h>
#include <unistd.h>

int main() {
    char buffer[128];
    int n = read(0, buffer, sizeof(buffer));  // 调用系统调用 sys_read()
    write(1, buffer, n);  // 调用系统调用 sys_write()
    return 0;
}

2.ioctl(I/O 控制)

原理:

ioctl()(I/O Control)是 系统调用,用于对设备驱动进行特殊操作,如配置 GPIO、电机控制、传感器读取等。

设备驱动程序通过 unlocked_ioctl 处理 ioctl 请求。

适用场景:

设备驱动程序的参数设置(如波特率、模式)

发送命令到内核

#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>

#define LED_ON  _IOW('L', 1, int)
#define LED_OFF _IOW('L', 2, int)

int main() {
    int fd = open("/dev/my_led", O_RDWR);
    if (fd < 0) {
        perror("open");
        return -1;
    }

    ioctl(fd, LED_ON);  // 控制 LED 亮
    ioctl(fd, LED_OFF); // 控制 LED 灭
    close(fd);
    return 0;
}

3. procfs(/proc 文件系统)

原理:

/proc 是一个虚拟文件系统,用于访问内核状态信息

通过 cat /proc/my_proc,可以获取内核数据。

适用场景:

进程信息(/proc/<PID>

内核参数(/proc/sys/

设备信息(/proc/devices

static struct proc_dir_entry *proc_entry;

ssize_t my_proc_read(struct file *file, char __user *buf, size_t count, loff_t *pos) {
    char message[] = "Hello from Kernel!\n";
    return simple_read_from_buffer(buf, count, pos, message, sizeof(message));
}

static int __init my_init(void) {
    proc_entry = proc_create("my_proc", 0444, NULL, &(struct proc_ops){ .proc_read = my_proc_read });
    return 0;
}
static void __exit my_exit(void) { remove_proc_entry("my_proc", NULL); }

用户程序访问:

cat /proc/my_proc

4. sysfs(/sys 文件系统)

原理:

/sys 是一个 /proc 更结构化 的文件系统,主要用于设备和驱动信息的交互。

可以用 echocat 直接修改或获取设备信息

适用场景:

设备驱动的参数调节(如 LED 亮度、风扇转速)

设备状态监测

static struct kobject *kobj;
static int my_value = 0;

static ssize_t show_value(struct kobject *kobj, struct kobj_attribute *attr, char *buf) {
    return sprintf(buf, "%d\n", my_value);
}
static ssize_t store_value(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) {
    sscanf(buf, "%d", &my_value);
    return count;
}

static struct kobj_attribute my_attr = __ATTR(my_value, 0660, show_value, store_value);

static int __init my_init(void) {
    kobj = kobject_create_and_add("my_kobj", kernel_kobj);
    sysfs_create_file(kobj, &my_attr.attr);
    return 0;
}

用户访问:

echo 10 > /sys/kernel/my_kobj/my_value  # 写入
cat /sys/kernel/my_kobj/my_value        # 读取
方式适用场景适合数据量复杂度
System Call通用
ioctl设备控制⭐⭐
procfs状态查询
sysfs设备参数
Netlink事件通知中等⭐⭐⭐
mmap大数据⭐⭐⭐

7.内核链表为什么具有通用性?

内核中由于要管理大量的设备,但是各种设备各不相同,必须将他们统一起来管理,于是内核设计者就想到了使用通用链表来处理,通用链表看似神秘,实际上就是双向循环链表,这个链表的每个节点都是只有指针域,没有任何数据域。

使用通用链表的好处是
1.通用链表中每个节点中没有数据域,也就是说无论数据结构有多复杂在链表中只有前后级指针。2.如果一个数据结构(即是描述设备的设备结构体)想要用通用链表管理,只需要在结构体中包含节
点的字段即可。
3.双向链表可以从任意一个节点的前后遍历整个链表,遍历非常方便。
4.使用循环链表使得可以不断地循环遍历管理节点,像进程的调度:操作系统会把就绪的进程放在一个管理进程的就绪队列的通用链表中管理起来,循环不断地,为他们分配时间片,获得cpu进行周而复始的进程调度。

注意:在RTOS操作系统中,每个task的执行顺序,不同状态,队列,信号量,互斥锁等等,底层都是使用链表的。

特性传统链表Linux 内核链表
是否绑定数据类型(只能存 int 或特定结构体)(适用于任何结构体)
是否循环
是否双向可能是单链表
是否支持统一 API(不同数据类型需要不同的操作)(统一 API)
是否易扩展扩展困难易扩展

8.应用程序中open()在linux中执行过程中是如何从用户空间到内核空间?

open() 是 Linux 系统调用(System Call)之一,用于打开文件或设备。它涉及从用户空间(User Space)切换到内核空间(Kernel Space)的过程,具体涉及系统调用、中断、文件系统、VFS(虚拟文件系统)等机制

如下是流程:

open() 先通过 glibc 触发系统调用

进入内核后,先由 VFS 解析路径

如果是普通文件,调用 ext4 等文件系统的 open

如果是设备文件,调用设备驱动 file_operations->open()

最终返回文件描述符 fd,用户进程可以使用 read()write() 操作

open()glibc(C 标准库) 中的实现:

int open(const char *pathname, int flags, mode_t mode) {
    return syscall(SYS_openat, AT_FDCWD, pathname, flags, mode);
}

syscall(SYS_openat, ...) 通过 syscall 指令 进入 内核空间

这个过程发生在 arch/x86/entry/entry_64.S,主要步骤:

syscall 指令:CPU 从用户模式(Ring 3)切换到内核模式(Ring 0)

sys_openat() 被调用(定义在 fs/open.c)。

fs/open.c 中:

long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode) {
    struct open_how how = build_open_how(flags, mode);
    return do_filp_open(dfd, filename, &how);
}

fs/namei.c

struct file *do_filp_open(int dfd, const char __user *filename, struct open_how *how) {
    struct nameidata nd;
    struct file *filp;
    filp = path_openat(&nd, how, LOOKUP_FOLLOW);
    return filp;
}

假设 open() 操作的是 ext4 文件:

  • VFS 通过 inode_operations->lookup() 找到 ext4_lookup()
  • 调用 file_operations->open()(如 ext4_file_open())。

ext4_file_open()(位于 fs/ext4/file.c):

int ext4_file_open(struct inode *inode, struct file *file) {
    // 执行特定文件系统的打开操作
    return generic_file_open(inode, file);
}
步骤主要操作
1. 用户空间调用glibc 调用 syscall(SYS_openat)
2. 进入内核空间syscall 指令触发 sys_openat()
3. VFS 处理do_filp_open() 解析路径,查找文件
4. 文件系统层ext4_file_open()device->fops->open()
5. 生成文件描述符fd 存入 task_struct->files 并返回

9.怎么申请大块内核内存?

vmalloc

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot+Vue的理解(含axios/ajax)-前后端交互前端篇

文章目录 引言SpringBootThymeleafVueSpringBootSpringBootVue&#xff08;前端&#xff09;axios/ajaxVue作用响应式动态绑定单页面应用SPA前端路由 前端路由URL和后端API URL的区别前端路由的数据从哪里来的 Vue和只用三件套axios区别 关于地址栏url和axios请求不一致VueJSPS…

网络直播时代的营销新策略:基于受众分析与开源AI智能名片2+1链动模式S2B2C商城小程序源码的探索

摘要&#xff1a;随着互联网技术的飞速发展&#xff0c;网络直播作为一种新兴的、极具影响力的媒体形式&#xff0c;正逐渐改变着人们的娱乐方式、消费习惯乃至社交模式。据中国互联网络信息中心数据显示&#xff0c;网络直播用户规模已达到3.25亿&#xff0c;占网民总数的45.8…

将ollama迁移到其他盘(eg:F盘)

文章目录 1.迁移ollama的安装目录2.修改环境变量3.验证 背景&#xff1a;在windows操作系统中进行操作 相关阅读 &#xff1a;本地部署deepseek模型步骤 1.迁移ollama的安装目录 因为ollama默认安装在C盘&#xff0c;所以只能安装好之后再进行手动迁移位置。 # 1.迁移Ollama可…

《Trustzone/TEE/安全从入门到精通-标准版》

CSDN学院课程连接:https://edu.csdn.net/course/detail/39573 讲师介绍 拥有 12 年手机安全、汽车安全、芯片安全开发经验,擅长 Trustzone/TEE/ 安全的设计与开发,对 ARM 架构的安全领域有着深入的研究和丰富的实践经验,能够将复杂的安全知识和处理器架构知识进行系统整…

手撕Diffusion系列 - 第十一期 - lora微调 - 基于Stable Diffusion(代码)

手撕Diffusion系列 - 第十一期 - lora微调 - 基于Stable Diffusion&#xff08;代码&#xff09; 目录 手撕Diffusion系列 - 第十一期 - lora微调 - 基于Stable Diffusion&#xff08;代码&#xff09;Stable Diffusion 原理图Stable Diffusion的原理解释Stable Diffusion 和Di…

基于 AWS SageMaker 对 DeepSeek-R1-Distilled-Llama-8B 模型的精调与实践

在当今人工智能蓬勃发展的时代&#xff0c;语言模型的性能优化和定制化成为研究与应用的关键方向。本文聚焦于 AWS SageMaker 平台上对 DeepSeek-R1-Distilled-Llama-8B 模型的精调实践&#xff0c;详细探讨这一过程中的技术细节、操作步骤以及实践价值。 一、实验背景与目标 …

三、SysTick系统节拍定时器

3.1 SysTick简介 系统节拍定时器SysTick是ARM Cortex-M0内核提供的一个24位递减定时器&#xff0c;当计数值达到0时产生中断&#xff0c;可以为操作系统和其他管理软件提供固定时间的中断。 当系统节拍定时器被被使能时&#xff0c;定时器从重装值递减计数&#xff0c;到0进中断…

算法每日双题精讲 —— 前缀和(【模板】一维前缀和,【模板】二维前缀和)

在算法竞赛与日常编程中&#xff0c;前缀和是一种极为实用的预处理技巧&#xff0c;能显著提升处理区间和问题的效率。今天&#xff0c;我们就来深入剖析一维前缀和与二维前缀和这两个经典模板。 一、【模板】一维前缀和 题目描述 给定一个长度为 n n n 的整数数组 a a a&…

学习数据结构(2)空间复杂度+顺序表

1.空间复杂度 &#xff08;1&#xff09;概念 空间复杂度也是一个数学表达式&#xff0c;表示一个算法在运行过程中根据算法的需要额外临时开辟的空间。 空间复杂度不是指程序占用了多少bytes的空间&#xff0c;因为常规情况每个对象大小差异不会很大&#xff0c;所以空间复杂…

MybatisX插件快速创建项目

一、安装插件 二、创建一个数据表测试 三、IDEA连接Mysql数据库 四、选择MybatiX构造器 五、配置参数 六、项目结构

基于SpringBoot的假期周边游平台的设计与实现(源码+SQL脚本+LW+部署讲解等)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

Java设计模式:结构型模式→组合模式

Java 组合模式详解 1. 定义 组合模式&#xff08;Composite Pattern&#xff09;是一种结构型设计模式&#xff0c;它允许将对象组合成树形结构以表示“部分-整体”的层次。组合模式使得客户端能够以统一的方式对待单个对象和对象集合的一致性&#xff0c;有助于处理树形结构…

FastReport.NET控件篇之富文本控件

简介 FastReport.NET 提供了 RichText 控件&#xff0c;用于在报表中显示富文本内容。富文本控件支持多种文本格式&#xff08;如字体、颜色、段落、表格、图片等&#xff09;&#xff0c;非常适合需要复杂排版和格式化的场景。 富文本控件(RichText)使用场景不多&#xff0c…

单片机基础模块学习——NE555芯片

一、NE555电路图 NE555也称555定时器,本文主要利用NE555产生方波发生电路。整个电路相当于频率可调的方波发生器。 通过调整电位器的阻值,方波的频率也随之改变。 RB3在开发板的位置如下图 测量方波信号的引脚为SIGHAL,由上面的电路图可知,NE555已经构成完整的方波发生电…

(done) MIT6.S081 2023 学习笔记 (Day6: LAB5 COW Fork)

网页&#xff1a;https://pdos.csail.mit.edu/6.S081/2023/labs/cow.html 任务1&#xff1a;Implement copy-on-write fork(hard) (完成) 现实中的问题如下&#xff1a; xv6中的fork()系统调用会将父进程的用户空间内存全部复制到子进程中。如果父进程很大&#xff0c;复制过程…

三天急速通关JavaWeb基础知识:Day 1 后端基础知识

三天急速通关JavaWeb基础知识&#xff1a;Day 1 后端基础知识 0 文章说明1 Http1.1 介绍1.2 通信过程1.3 报文 Message1.3.1 请求报文 Request Message1.3.2 响应报文 Response Message 2 XML2.1 介绍2.2 利用Java解析XML 3 Tomcat3.1 介绍3.2 Tomcat的安装与配置3.3 Tomcat的项…

SQLServer 不允许保存更改(主键)

在我们进行数据库表格编辑的时候,往往会出现同一个名字,就比如我们的账号一样,我们在注册自己QQ的时候,我们通常注册过的账号,别人就不能注册了,这是为了保证严密性 所以我们需要点击表格>右键>设计 点击某一列>右键>设计主键 当我们Ctrls 保存的时候回弹出下…

【hot100】刷题记录(6)-轮转数组

题目描述&#xff1a; 给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数。 示例 1: 输入: nums [1,2,3,4,5,6,7], k 3 输出: [5,6,7,1,2,3,4] 解释: 向右轮转 1 步: [7,1,2,3,4,5,6] 向右轮转 2 步: [6,7,1,2,3,4,5] 向右轮转…

(非技术)从一公里到半程马拉松:我的一年跑步经历

在24年初&#xff0c;从来不运动的我&#xff0c;连跑步一公里都不能完成。而在一年之后的2025年的1月1日&#xff0c;我参加了上海的蒸蒸日上迎新跑&#xff0c;完成了半程马拉松。虽然速度不快&#xff0c;也并不是什么特别难完成的事情&#xff0c;但对我来说还是挺有意义的…

知识蒸馏技术原理详解:从软标签到模型压缩的实现机制

知识蒸馏是一种通过性能与模型规模的权衡来实现模型压缩的技术。其核心思想是将较大规模模型&#xff08;称为教师模型&#xff09;中的知识迁移到规模较小的模型&#xff08;称为学生模型&#xff09;中。本文将深入探讨知识迁移的具体实现机制。 知识蒸馏原理 知识蒸馏的核心…