Linux内存映射

news2025/1/7 7:14:36

目录

背景

一、什么是内存映射?        

 二、mman函数

 1.权限问题

2.总线错误 

3.内存权限

4.读文件内容

5.映射与文件

 6.非法参数错误

 7.偏移量大小

 8.映射内存大小

8.1 申请6k,访问5k

8.2 申请2k,访问3k

8.3 返回值检查

三、内存映射实现

 四、匿名内存映射

 五、munmap函数


背景

        在传统的文件访问中,进程通常使用系统调用(例如open()read()write()close()等)来操作文件。这些系统调用允许进程打开文件、从文件中读取数据、向文件中写入数据以及关闭文件。这种方法需要通过系统调用在用户空间和内核空间之间进行数据传输,因此可能会产生一定的性能开销。  

        而使用内存映射技术,即将文件的内容映射到进程的虚拟内存空间中,使得进程可以直接访问内存而无需通过系统调用来读取或写入文件的内容。这样做可以提高文件访问的效率,因为读写文件的操作直接转化为对内存的操作,避免了频繁的系统调用。

        内存映射是一种将磁盘文件的内容映射到进程的虚拟内存空间中的技术。这意味着文件的内容被映射到进程的地址空间中,使得进程可以直接通过访问内存的方式来读取或写入文件的内容,而无需调用传统的read和write系统调用。这种方式能够提高对文件的访问效率,并且简化了对文件的操作。

内存映射的主要优点包括:

  1. 性能优势:由于文件内容直接映射到了内存中,因此读取文件的操作可以直接通过内存访问完成,避免了频繁的磁盘IO操作,从而提高了读取文件的速度。

  2. 简化操作:通过内存映射,文件被映射到了进程的地址空间中,进程可以像操作内存一样对文件进行读写,这样就简化了对文件的操作流程。

  3. 共享内存:多个进程可以共享同一个文件的内存映射,这样可以实现进程间的数据共享,而无需进行显式的数据传输。

一、什么是内存映射?        

        使一个磁盘文件与内存中的一个缓冲区相映射,进程可以像访问普通内存一样对文件进行访问,不必再调用read,write。

 二、mman函数

 void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);                

功能:创建共享内存映射

函数返回值:成功返回创建的映射区首地址,失败返回MAP_FAILED( ((void *) -1) ),设置errno值。

参数说明:


addr:指定要映射的内存地址,一般设置为 NULL 让操作系统自动选择合适的内存地址。

length:必须>0。映射地址空间的字节数,它从被映射文件开头 offset 个字节开始算起。

prot:指定共享内存的访问权限。
可取如下几个值的可选:
    PROT_READ(可读), 
    PROT_WRITE(可写), 
    PROT_EXEC(可执行),
    PROT_NONE(不可访问)。

flags:由以下几个常值指定:
    MAP_SHARED(共享的),
    MAP_PRIVATE(私有的), 
    MAP_ANONYMOUS(匿名映射,用于血缘关系进程间通信)
    MAP_FIXED(表示必须使用 start 参数作为开始地址,如果失败不进行修正),
    其中,MAP_SHARED , MAP_PRIVATE必选其一,而 MAP_FIXED 则不推荐使用。
   
fd:表示要映射的文件句柄。如果匿名映射写-1。

offset:表示映射文件的偏移量,一般设置为 0 表示从文件头部开始映射。

注意事项:

 1.权限问题

#include<stdio.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/mman.h>
#include<unistd.h>

int main()
{
	void* addr;
	int fd;
	fd = open("test",O_RDONLY);
	if(fd < 0)
	{
		perror("open");
		return 0;
	}
//	int len = lseek(fd,0,SEEK_END);
	addr = mmap(NULL,2048,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);
	if(addr == MAP_FAILED)
	{
		perror("mmap");
		return 0;
	}
	return 0;
}

 文件的打开权限是只读,运行结果为:Permission denied

linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ gcc -o mman mman.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ ./mman
mmap: Permission denied
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ cat mman.c

 文件打开权限修改为可读可写即可,因为PROT_READ | PROT_WRITE为可读可写,要求:

        当MAP_SHARED时,要求:映射区的权限应 <=文件打开的权限(出于对映射区的保护),如果不满足报非法参数(Invalid argument)错误。

2.总线错误 

        用于映射的文件大小必须>0,当映射文件大小为0时,指定非0大小创建映射区,访问映射地址会报总线错误

#include<stdio.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/mman.h>
#include<unistd.h>

int main()
{
	void* addr;
	int fd;
	fd = open("test",O_RDWR);
	if(fd < 0)
	{
		perror("open");
		return 0;
	}
//	int len = lseek(fd,0,SEEK_END);
	addr = mmap(NULL,2048,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);
	if(addr == MAP_FAILED)
	{
		perror("mmap");
		return 0;
	}


	memcpy(addr,"abcdefg",7);
	return 0;
}
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ gcc -o mman mman.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ ./mman
Bus error (core dumped)
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ 

test文件里为空, 不满足:用于映射的文件大小必须>0。直接在test里加个空格都行。

linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ cat test
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ vim test
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ cat test
 
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ ./mman
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ cat test
ablinux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ 

文件足够大,就可以显示出abcdef:

ablinux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ vim test
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ ls -l test
-rwxrwxrwx 1 root root 104 Mar  8 00:44 test
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ ./mman
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ cat test
abcdefg                                         

3.内存权限

	addr = mmap(NULL,2048,PROT_READ | PROT_WRITE,MAP_PRIVATE,fd,0);

        当MAP_PRIVATE时候,mmap中的权限是对内存的限制,只需要文件有读权限即可,操作只在内存有效,不会写到物理磁盘,且不能在进程间共享。

linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ gcc -o mman mman.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ ./mman
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ cat test
                                   
              
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ vim test

4.读文件内容

        注意进行强制类型转换,不然会有警告。

	printf("read = %s\n",(char*)addr);	
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ vim mman.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ gcc -o mman mman.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ ./mman
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ cat test
abcdefg                            
              
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ vim mman.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ gcc -o mman mman.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ ./mman
read = abcdefg                            
              

5.映射与文件

        映射区的释放与文件关闭无关,只要映射建立成功,文件可以立即关闭。

linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ vim mman.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ gcc -o mman mman.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ ./mman
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ cat test
999999999                          
           
int main()
{
	void* addr;
	int fd;
	fd = open("test",O_RDWR);
	if(fd < 0)
	{
		perror("open");
		return 0;
	}
//	int len = lseek(fd,0,SEEK_END);
	addr = mmap(NULL,2048,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);
	if(addr == MAP_FAILED)
	{
		perror("mmap");
		return 0;
	}
	close(fd);

	memcpy(addr,"999999999",9);

//	printf("read = %s\n",(char*)addr);	
	return 0;
}

 6.非法参数错误

        指定0大小创建映射区,报非法参数错误(Invalid argument)

	addr = mmap(NULL,0,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ vim mman.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ gcc -o mman mman.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ ./mman
mmap: Invalid argument
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ 

可以通过lseek取文件大小

int len = lseek(fd,0,SEEK_END);
printf("%d\n",len);
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ ls -l test
-rwxrwxrwx 1 root root 51 Mar  8 01:20 test
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ ./mman
51
read = 999999999                          
              

linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ 
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int filedes, off_t offset, int whence) ;

返回值:成功:返回文件新的偏移量(成功) 

lessk()函数的参数说明:
第一个参数是文件描述符;
第二个参数是偏移量,
参数 offset可正可负,负数时向文件开头偏移,正数相对于文件末尾偏移
第三个参数是有三个选项:
1.SEEK_SET:将文件指针偏移到传入字节数处(文件头开始偏移)
2.SEEK_CUR:将文件指针偏移到当前位置加上传入字节数处;((当前位置开始偏移)
3.SEEK_END:将文件指针偏移到文件末尾加上传入字节数处(作为拓展作用,必须再执行一次写操作)

 7.偏移量大小

        文件偏移量必须为0或者4K的整数倍(不是,会报非法参数Invalid argument错误)

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
最后一个参数是偏移量  
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ vim mman.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ gcc -o mman mman.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ ./mman
mmap: Invalid argument
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ 
	addr = mmap(NULL,len,PROT_READ | PROT_WRITE,MAP_SHARED,fd,1);

 8.映射内存大小

        映射大小可以大于文件大小,但只能访问文件page的内存地址,否则报总线错误 ,超出映射的内存大小报段错误。

        实际是根据文件大小分配空间的,文件大小是51。你申请2k的空间,实际分配的是4k的空间,而你申请6k,实际分配的还是4k空间,所以报总线错误。

8.1 申请6k,访问5k
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ vim mman.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ gcc -o mman mman.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ ./mman
Bus error (core dumped)
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ 

	addr = mmap(NULL,6000,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);
	memcpy((addr+5000),"999999999",9);
8.2 申请2k,访问3k
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ vim mman.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ gcc -o mman mman.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ ./mman
read = 999999999
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ 
	addr = mmap(NULL,2000,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);
	memcpy((addr+3000),"999999999",9);

 

8.3 返回值检查

        mmap创建映射区出错概率非常高,一定要检查返回值,确保映射区建立成功再进行后续操作。

    void* addr;    
    addr = mmap(NULL,2048,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);
	if(addr == MAP_FAILED)
	{
		perror("mmap");
		return 0;
	}

三、内存映射实现

 mmanw.c

#include<stdio.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/mman.h>
#include<unistd.h>

int main()
{
	void* addr;
	int fd;
	fd = open("test",O_RDWR);
	if(fd < 0)
	{
		perror("open");
		return 0;
	}
	int len = lseek(fd,0,SEEK_END);
	addr = mmap(NULL,2048,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);
	if(addr == MAP_FAILED)
	{
		perror("mmap");
		return 0;
	}
	close(fd);
	int i = 0;
	while(i<2048)
	{
		memcpy((addr+i),"a",1);
		i++;
		sleep(1);
	}
	return 0;
}

mmanr.c

#include<stdio.h>

#include<sys/stat.h>
#include<fcntl.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/mman.h>
#include<unistd.h>

int main()
{
	void* addr;
	int fd;
	fd = open("test",O_RDWR);
	if(fd < 0)
	{
		perror("open");
		return 0;
	}
	int len = lseek(fd,0,SEEK_END);
	addr = mmap(NULL,2048,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);
	if(addr == MAP_FAILED)
	{
		perror("mmap");
		return 0;
	}
	close(fd);
	while(1)
	{
		printf("read = %s\n",(char*)(addr));
		sleep(1);
	}
	return 0;
}

 四、匿名内存映射

        void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);                

         fd:表示要映射的文件句柄。如果匿名映射写-1。

        匿名映射适用于具有亲缘关系的进程之间。

linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ gcc -o mmap_n mmap_n.c
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ ./mmap_n.c
./mmap_n.c: line 13: syntax error near unexpected token `('
./mmap_n.c: line 13: `int main()'
linux@linux:/mnt/hgfs/linuxshare/linux_code/mman$ ./mmap_n
read father value = 1234567890
#include<stdio.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/mman.h>
#include<unistd.h>
#include<sys/wait.h>
#include<sys/types.h>


int main()
{
	void* addr;
	//匿名映射不需要文件操作

	addr = mmap(NULL,2048,PROT_READ | PROT_WRITE,MAP_SHARED | MAP_ANONYMOUS,-1,0);
	if(addr == MAP_FAILED)
	{
		perror("mmap");
		return 0;
	}
	

	pid_t pid;
	pid = fork();
	if(pid < 0)
	{
		perror("pid");
		return 0;
	}
	else if(pid > 0)
	{
		memcpy(addr,"1234567890",10);

		wait(NULL);
	}
	else
	{
		sleep(1);
		printf("read father value = %s\n",(char*)addr);
	}

	return 0;
}

        使用mmap函数创建一个大小为2048字节的共享内存区域。mmap的第一个参数是指定的映射地址(这里为NULL表示由系统决定),然后指定映射的大小为2048字节,设置读写权限为可读可写,使用MAP_SHARED标志来创建一个共享映射,MAP_ANONYMOUS标志表示不与任何文件关联 。

        使用fork函数创建一个子进程。如果fork返回负值,则表示创建失败,父进程会输出错误信息并退出。如果fork返回0,则表示当前代码运行在子进程中,子进程将等待1秒后,从共享内存中读取数据并打印输出。如果fork返回正值,则表示当前代码运行在父进程中,父进程使用memcpy将字符串"1234567890"复制到共享内存中,然后等待子进程结束。

为什么?

父进程在写入数据后,可能会导致子进程读取数据,
而如果父进程提前退出,操作系统会清理共享内存,
这可能导致子进程读取到的数据不完整或者无效。

通过调用wait(NULL),父进程等待子进程执行完毕,
确保子进程能够正常读取共享内存中的数据。
只有在子进程执行完毕后,父进程才会继续执行后续的操作,包括退出程序,
这样就不会导致共享内存被提前清理。

 

 五、munmap函数

int munmap(void *addr, size_t length);

​​​​​​​返回值:成功返回0,失败返回-1,并设置errno值。

函数参数:

addr:调用mmap函数成功返回的映射区首地址

length:映射区大小(即:mmap函数的第二个参数)

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

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

相关文章

【Windows】VMware虚拟机应用(二):安装ubuntu-14.04.4

一、下载安装包 ubuntu-14.04.4-server-amd64.iso 注&#xff1a;因为我是用已有的安装包&#xff0c;所以&#xff0c;这里就不写下载步骤了。 二、安装引导 以管理员身份运行 VMware Workstation Pro 注&#xff1a;如果不是管理员身份运行&#xff0c;在安装系统时会出现…

Redis入门到实战-黑马程序员

文章目录 Redis安装与启动Redis的安装启动RedisRedis客户端Redis通用命令key的层级格式 Redis五种数据类型StringHashListSetSortedSet Redis安装与启动 Redis的安装 Redis是基于C语言编写的&#xff0c;因此首先需要安装Redis所需要的gcc依赖&#xff1a; Linux安装Redis步…

能源管理系统是怎么实现节能减排的?

在这个环保意识日益增强的时代&#xff0c;我们都在寻找更智能、更绿色的生活方式。你是否想过&#xff0c;家里的电表、空调、照明系统其实可以协同工作&#xff0c;帮助我们节约能源&#xff0c;减少碳足迹呢&#xff1f;这就是神奇的能源管理系统在发挥作用&#xff01; 能…

线程安全——使用线程安全函数,多线程中执行fork引发的问题及如何解决

目录 一、引例 二、线程安全 三、多线程中执行fork 3.1 多线程中某个线程调用 fork()&#xff0c;子进程会有和父进程相同数量的线程吗? 3.2 父进程被加锁的互斥锁 fork 后在子进程中是否已经加锁 一、引例 在主线程和函数线程中进行语句分割并输出。 #include <stdi…

vite+ts+vue3 项目搭建和基础配置

官网: 文件夹cdm进入小黑窗, 按步骤安装项目即可, 用到的都选 "是" 快速上手 | Vue.jsVue.js - 渐进式的 JavaScript 框架https://cn.vuejs.org/guide/quick-start.html安装成功后目录如下: index.html 尾部报错: cleareslint(vue/comment-directive), 已知 是eslin…

新书速览|FFmpeg开发实战:从零基础到短视频上线

资深音视频开发专家、畅销书作者重磅新作&#xff0c;从基础知识到高级应用&#xff0c;从桌面开发到移动开发&#xff0c;9大实际音视频项目完整再现 本书内容 《FFmpeg开发实战&#xff1a;从零基础到短视频上线》是一本FFmpeg开发的实战教程&#xff0c;由浅入深&#xff0…

vite+vue3门户网站菜单栏动态路由控制

门户网站用户端需要分板块展示&#xff0c;板块内容由管理端配置&#xff0c;包括板块名称&#xff0c;访问路径&#xff0c;路由组件&#xff0c;展示顺序&#xff0c;是否展示。如下图所示&#xff1a; 用户访问门户网站时&#xff0c;展示菜单跳转通过板块配置&#xff0c;动…

Leetcode : 1137. 高度检查器

学校打算为全体学生拍一张年度纪念照。根据要求&#xff0c;学生需要按照 非递减 的高度顺序排成一行。 排序后的高度情况用整数数组 expected 表示&#xff0c;其中 expected[i] 是预计排在这一行中第 i 位的学生的高度&#xff08;下标从 0 开始&#xff09;。 给你一个整数…

Web3 Summit 2024 柏林重启:与全球 Buidler 共赴创新盛事

时隔五年&#xff0c;Web3 Summit 将于 8 月 19 日至 21 日回归柏林举办。 2019 年&#xff0c;1000 多名开发人员、研究人员和 buidler 齐聚一堂&#xff0c;参加了上一届为期三天的 Web3 Summit&#xff0c;这是一个所有致力于促进在去中心化网络上深耕团队相聚的盛事。 与…

RDB 和 AOF 的实现原理以及优缺点

一个工作了 5 年的粉丝私信我&#xff0c; 关于 RDB 和 AOF 的实现原理 这个问题在面试的时候&#xff0c;应该怎么回答&#xff1f;于是我把之前整理过的一个高手回答整理成文档发给了他&#xff0c;后来他参考这个回复在面试的时候顺利拿到了 offer 今天我把这个文档分享给大…

AI大模型,掀起新一波智能浪潮!

AI大模型的出现&#xff0c;标志着人工智能技术迈入了一个新的阶段。这些巨大的模型不仅在规模上超越了以往任何其他人工智能系统&#xff0c;而且在性能上也取得了巨大的突破。由于其庞大的参数量和复杂的结构&#xff0c;AI大模型在各个领域展现出了强大的学习能力和推理能力…

Haproxy 负载均衡集群

一. Haproxy 1. Haproxy 介绍 HAProxy 是法国开发者威利塔罗 (Willy Tarreau) 在2000年使用C语言开发的一个开源软件&#xff0c;是一款具备高并发(一万以上)、高性能的TCP和HTTP负载均衡器&#xff0c;支持基于cookie的持久性&#xff0c;自动故障切换&#xff0c;支持正则…

基于React低代码平台开发:直击最新应用构建

文章目录 前言一、React与低代码平台的结合优势二、基于React的低代码平台开发挑战三、基于React的低代码平台开发实践四、未来展望《低代码平台开发实践&#xff1a;基于React》编辑推荐内容简介作者简介目录前言为什么要写这本书读者对象如何阅读本书 前言 随着数字化转型的…

【免费资源】Unity真实广阔的沙漠场景等你来解锁!

Unity真实广阔的沙漠场景等你来解锁&#xff01; Unity 每周免费资源上新啦&#xff01;此次更新的是广阔的沙漠场景&#xff0c;其中包含 14 个预制体&#xff0c;每个预制体都包含 LOD、400-2000 顶点和 4K 纹理。现在&#xff0c;只需登录 Asset Store&#xff0c;即可免费领…

ThinkPHP6与支付宝支付集成指南:轻松实现在线收款!

随着移动支付的普及&#xff0c;支付宝成为了越来越多人的首选支付方式。而作为一款高性能、高效率、安全稳定的开源框架&#xff0c;thinkphp6也被众多开发人员所青睐。那么&#xff0c;如何在thinkphp6中快速简便地实现支付宝支付呢&#xff1f; 首先&#xff0c;我们需要在…

openGauss学习笔记-238 openGauss性能调优-SQL调优-SQL执行计划介绍-详解

文章目录 openGauss学习笔记-238 openGauss性能调优-SQL调优-SQL执行计划介绍-详解238.1 详解238.1.1 执行计划238.1.1.1 执行计划层级解读&#xff08;纵向&#xff09;238.1.1.2 执行计划中的关键字说明 238.1.2 执行信息 openGauss学习笔记-238 openGauss性能调优-SQL调优-S…

机器学习-可解释性机器学习:随机森林与fastshap的可视化模型解析

一、引言 机器学习在当今社会扮演着日益重要的角色&#xff0c;但黑盒模型的不可解释性限制了其应用范围。因此&#xff0c;可解释性机器学习成为研究热点&#xff0c;有助于提高模型的可信度和可接受性。本文旨在探讨随机森林和fastshap作为可视化模型解析工具的应用&#xff…

nodejs web服务器 -- 搭建开发环境

一、配置目录结构 1、使用npm生成package.json&#xff0c;我创建了一个nodejs_network 文件夹&#xff0c;cd到这个文件夹下&#xff0c;执行&#xff1a; npm init -y 其中-y的含义是yes的意思&#xff0c;在init的时候省去了敲回车的步骤&#xff0c;如此就生成了默认的pac…

Mysql学习笔记之事务详解(读未提交、读以提交、可重复读、串行化读)

在这个博主的基础上&#xff0c;增加两种情况的对比&#xff1a;https://blog.csdn.net/llllllkkkkkooooo/article/details/108068919 可重复读中幻读现象&#xff08;未使用MVCC&#xff09; 设置可重复读的隔离级别 set global transaction isolation level repeatable read…