操作系统--Linux虚拟内存管理

​一、什么是虚拟内存地址

收货地址是一个虚拟地址,它是人为定义的

而我们的城市,小区,街道是真实存在的,他们的地理位置就是物理地址

以 Intel Core i7 处理器为例,64 位和32位虚拟地址的格式为:


二、为什么要使用虚拟地址访问内存

进程虚拟内存空间中的每一个字节都有与其对应的虚拟内存地址

一个虚拟内存地址表示进程虚拟内存空间中的一个特定的字节

如果不使用虚拟地址,而是直接操作物理内存,我们需要知道每一个变量的位置都被安排在了哪里,而且还要注意和多个进程同时运行的时候,不能共用同一个地址,否则就会造成地址冲突。

 

而虚拟内存的引入正是要解决上述的问题,虚拟内存引入之后,每个进程都拥有自己独立的虚拟地址空间,进程与进程之间的虚拟内存地址空间是相互隔离,互不干扰的。每个进程都认为自己独占所有内存空间,自己想干什么就干什么。


三、进程虚拟内存空间

一个进程运行起来是为了执行我们交代给进程的工作,执行这些工作的步骤我们通过程序代码事先编写好,然后编译成二进制文件存放在磁盘中,CPU 会执行二进制文件中的机器码来驱动进程的运行。

内核根据进程运行的过程中所需要不同种类的数据而为其开辟了对应的地址空间。分别为:

编译期间(程序运行前)

  • 代码段:用于存放进程程序二进制文件中的机器指令

  • 数据段:用于存放程序二进制文件中指定了初始值的全局变量和静态变量

  • BSS 段:用于存放程序二进制文件中没有指定初始值的全局变量和静态变量,这些未初始化的全局变量被加载进内存之后会被初始化为 0 值

程序运行期间

  • :用于在程序运行过程中动态申请内存的,指的是 OS 堆并不是 JVM 中的堆

  • 文件映射与匿名映射区:用于存放动态链接库以及内存映射区域的文件映射与匿名映射区

  • :用于存放函数调用过程中的局部变量和函数参数


四、Linux进程虚拟内存空间

4.1 32位机器上进程虚拟内存空间分布

32 位机器上,指针的寻址范围为 2^32,所能表达的虚拟内存空间为 4 GB

  • 总虚拟内存空间为 4 GB,总虚拟内存地址范围为:0x0000 0000 - 0xFFFF FFFF
  • 用户态虚拟内存空间为 3 GB,虚拟内存地址范围为:0x0000 0000 - 0xC000 000
  • 内核态虚拟内存空间为 1 GB,虚拟内存地址范围为:0xC000 000 - 0xFFFF FFFF
  • 0x0000 0000 到 0x0804 8000 这段虚拟内存地址是一段不可访问的保留区,因为在大多数操作系统中,数值比较小的地址通常被认为不是一个合法的地址,这块小地址是不允许访问的。比如在 C 语言中我们通常会将一些无效的指针设置为 NULL,指向这块不允许访问的地址
  • 代码段和数据段,它们是从程序的二进制文件中直接加载进内存中的
  • BSS 段中的数据也存在于二进制文件中,因为内核知道这些数据是没有初值的,所以在二进制文件中只会记录 BSS 段的大小,在加载进内存时会生成一段 0 填充的内存空间
  • 空间中地址的增长方向是从低地址到高地址增长。
  • 堆空间的上边是一段待分配区域,用于扩展堆空间的使用。
  • 文件映射与匿名映射区的地址增长方向是从高地址向低地址增长。进程运行时所依赖的动态链接库中的代码段,数据段,BSS 段就加载在这里。还有我们调用 mmap 映射出来的一段虚拟内存空间也保存在这个区域。
  • 在栈空间的下边也有一段待分配区域用于扩展栈空间。
  • 空间中的地址增长方向是从高地址向低地址增长。这里会保存函数运行过程所需要的局部变量以及函数参数等函数调用信息。每次进程申请新的栈地址时,其地址值是在减少的。
  • 在栈空间的上边就是内核空间了,进程虽然可以看到这段内核空间地址,但是就是不能访问。

4.2 64位机器上进程虚拟内存空间分布


目前的 64 位系统下只使用了 48 位来描述虚拟内存空间,寻址范围为 2^48 ,所能表达的虚拟内存空间为 256TB

  • 总虚拟内存空间为 256TB,总虚拟内存地址范围为:0x0000 0000 0000 0000 0000 - 0xFFFF FFFF FFFF FFFF
  • 用户态虚拟内存空间为128T,虚拟内存地址范围为:0x0000 0000 0000 0000 - 0x0000 7FFF FFFF F000
  • 内核态虚拟内存空间为128T,虚拟内存地址范围为:0xFFFF 8000 0000 0000 - 0xFFFF FFFF FFFF FFFF

64 位系统中的虚拟内存布局和 32 位系统中的虚拟内存布局大体上是差不多的。主要不同的地方有三点:

  • 就是前边提到的由高 16 位空闲地址造成的 canonical address 空洞。在这段范围内的虚拟内存地址是不合法的,因为它的高 16 位既不全为 0 也不全为 1,不是一个 canonical address,所以称之为 canonical address 空洞

  • 在代码段跟数据段的中间还有一段不可以读写的保护段,它的作用是防止程序在读写数据段的时候越界访问到代码段,这个保护段可以让越界访问行为直接崩溃,防止它继续往下运行。

  • 用户态虚拟内存空间与内核态虚拟内存空间分别占用 128T,其中低128T 分配给用户态虚拟内存空间,高 128T 分配给内核态虚拟内存空间。


五、进程虚拟内存空间的管理

内核如何为进程管理这些虚拟内存区域呢?

内核中的描述符 task_struct 结构

包含专门描述进程虚拟地址空间的内存描述符 mm_struct 结构,这个结构体中包含了前边几个小节中介绍的进程虚拟内存空间的全部信息。

每个进程都有唯一的 mm_struct 结构体,也就是前边提到的每个进程的虚拟地址空间都是独立,互不干扰的。

通过 fork() 函数创建出的子进程,它的虚拟内存空间以及相关页表相当于父进程虚拟内存空间的一份拷贝,直接从父进程中拷贝到子进程中。

  1. 当我们调用 fork() 函数创建进程的时候,表示进程地址空间的 mm_struct 结构会随着进程描述符 task_struct 的创建而创建。
  2. 随后会在 copy_process 函数中创建 task_struct 结构,并拷贝父进程的相关资源到新进程的 task_struct 结构里,其中就包括拷贝父进程的虚拟内存空间 mm_struct 结构。这里可以看出子进程在新创建出来之后它的虚拟内存空间是和父进程的虚拟内存空间一模一样的,直接拷贝过来
  3. 这里我们重点关注 copy_mm 函数,正是在这里完成了子进程虚拟内存空间 mm_struct 结构的的创建以及初始化。 copy_mm 函数首先会将父进程的虚拟内存空间 current->mm 赋值给指针 oldmm。然后通过 dup_mm 函数将父进程的虚拟内存空间以及相关页表拷贝到子进程的 mm_struct 结构中。最后将拷贝出来的 mm_struct 赋值给子进程的 task_struct 结构。

通过 vfork 或者 clone 系统调用创建出的子进程,父子进程之间使用的虚拟内存空间是一样的,并不是一份拷贝。

  1.  设置 CLONE_VM 标识
  2. 来到 copy_mm 函数中就会进入 if (clone_flags & CLONE_VM) 条件中,在这个分支中会将父进程的虚拟内存空间以及相关页表直接赋值给子进程,这样一来父进程和子进程的虚拟内存空间就变成共享的了

子进程共享了父进程的虚拟内存空间,这样子进程就变成了我们熟悉的线程是否共享地址空间几乎是进程和线程之间的本质区别。Linux 内核并不区别对待它们,线程对于内核来说仅仅是一个共享特定资源的进程而已。

内核线程和用户态线程的区别就是内核线程没有相关的内存描述符 mm_struct ,内核线程对应的 task_struct 结构中的 mm 域指向 Null,所以内核线程之间调度是不涉及地址空间切换的。

父进程与子进程的区别,进程与线程的区别,以及内核线程与用户态线程的区别其实都是围绕着这个 mm_struct 展开的。

5.1 内核如何划分用户态和内核态虚拟内存空间

这就用到了进程的内存描述符 mm_struct 结构体中的 task_size 变量,task_size 定义了用户态地址空间与内核态地址空间之间的分界线。

  • 32 位系统中用户地址空间和内核地址空间的分界线在 0xC000 000 地址处,那么自然进程的 mm_struct 结构中的 task_size 为 0xC000 000。
  • 64 位系统中用户地址空间和内核地址空间的分界线在 0x0000 7FFF FFFF F000 地址处,那么自然进程的 mm_struct 结构中的 task_size 为 0x0000 7FFF FFFF F000 。

5.2 内核如何布局不同进程虚拟内存空间

进程的内存描述符mm_struct 结构体内部


struct mm_struct {
/*-------------------------------------------------------------------------------*/
//内核中用 mm_struct 结构体中的下述“属性”来定义虚拟内存空间里的“不同内存区域”
/*-------------------------------------------------------------------------------*/unsigned long task_size;               /* size of task vm space *///task_size 是内核空间 和 用户态空间分界线,也标志着用户态空间的起始位置unsigned long start_code, end_code, start_data, end_data;//start_code 和 end_code 定义“代码段”的起始和结束位置//start_data 和 end_data 定义“数据段”的起始和结束位置//紧挨着“BSS段”,用于存放未被初始化的全局变量和静态变量,这些变量在加载进内存时会生成一段 0 填充的内存区域 (BSS段), BSS 段的大小是固定的unsigned long start_brk, brk, start_stack;//start_brk 和 brk 定义“OS堆”的起始和当前的结束位置//start_stack 是“栈”的起始位置在 RBP 寄存器中存储,栈的结束位置也就是栈顶指针 stack pointer 在 RSP 寄存器中存储unsigned long arg_start, arg_end, env_start, env_end;//arg_start 和 arg_end 是参数列表的位置//env_start 和 env_end 是环境变量的位置//它们都位于“栈”中的最高地址处unsigned long mmap_base;              /* base of mmap area *///mmap_base 定义“内存映射区”的起始地址
/*-------------------------------------------------------------------------------*/
//虚拟内存与物理内存映射内容相关的统计变量
/*-------------------------------------------------------------------------------*/unsigned long total_vm;               /* Total pages mapped *///total_vm 表示在进程虚拟内存空间中总共与物理内存映射的页的总数unsigned long locked_vm;              /* Pages that have PG_mlocked set *///locked_vm 就是被锁定不能换出的内存页总数unsigned long pinned_vm;              /* Refcount permanently increased *///pinned_vm 表示既不能换出,也不能移动的内存页总数
/*-------------------------------------------------------------------------------*/    
//进程虚拟内存空间中的虚拟内存使用情况
/*-------------------------------------------------------------------------------*/unsigned long data_vm;                /* VM_WRITE & ~VM_SHARED & ~VM_STACK *///data_vm 表示数据段中映射的内存页数目unsigned long exec_vm;                /* VM_EXEC & ~VM_WRITE & ~VM_STACK *///exec_vm 是代码段中存放可执行文件的内存页数目unsigned long stack_vm;               /* VM_STACK *///stack_vm 是栈中所映射的内存页数目...... 省略 ........
}

5.3 内核如何管理不同类型的虚拟内存区域

每个虚拟内存区域VMA的内存描述符vm_area_struct结构体内部

每个 vm_area_struct 结构对应于虚拟内存空间中的唯一虚拟内存区域 VMA

struct vm_area_struct {unsigned long vm_start;		/* Our start address within vm_mm. *///vm_start 指向了这块虚拟内存区域的起始地址(最低地址),vm_start 本身包含在这块虚拟内存区域内unsigned long vm_end;		/* The first byte after our end address within vm_mm. *///vm_end 指向了这块虚拟内存区域的结束地址(最高地址),而 vm_end 本身包含在这块虚拟内存区域之外//vm_area_struct 结构描述的是 [vm_start,vm_end) 这样一段左闭右开的虚拟内存区域/** Access permissions of this VMA.*/pgprot_t vm_page_prot;//页表中关于内存页的访问权限就是由 vm_page_prot 决定的unsigned long vm_flags;	//vm_flags 则偏向于定于整个虚拟内存区域的访问权限以及行为规范//和虚拟内存映射相关//虚拟内存区域可以映射到物理内存上,也可以映射到文件中,映射到物理内存上我们称之为匿名映射,映射到文件中我们称之为文件映射struct anon_vma *anon_vma;	/* Serialized by page_table_lock *///调用 mmap 进行匿名映射时,匿名映射区域就用 struct anon_vma 结构表示struct file * vm_file;		/* File we map to (can be NULL). *///调用 mmap 进行文件映射时,vm_file 属性就用来关联被映射的文件unsigned long vm_pgoff;		/* Offset (within vm_file) in PAGE_SIZE units */	//vm_pgoff 则表示映射进虚拟内存中的文件内容,在文件中的偏移void * vm_private_data;		/* was vm_pte (shared mem) *///vm_private_data 则用于存储 VMA 中的私有数据。具体的存储内容和内存映射的类型有关/* Function pointers to deal with this struct. */const struct vm_operations_struct *vm_ops;//struct vm_operations_struct 结构中定义的都是对虚拟内存区域 VMA 的相关操作函数指针//vm_ops 用来指向针对虚拟内存区域 VMA 的相关操作的函数指针
}

5.4 内核如何组织不同进程不同类型虚拟内存区域

内核的内存描述符vm_area_struct结构体内部(与组织结构相关的一些属性)

struct vm_area_struct {struct vm_area_struct *vm_next, *vm_prev;//在内核中其实是通过一个 struct vm_area_struct 结构的双向链表将虚拟内存空间中的这些虚拟内存区域 VMA 串联起来的// vm_next ,vm_prev 指针分别指向 VMA 节点所在双向链表中的后继节点和前驱节点,内核中的这个 VMA 双向链表是有顺序的,所有 VMA 节点按照低地址到高地址的增长方向排序//双向链表中的最后一个 VMA 节点的 vm_next 指针指向 NULL,双向链表的头指针存储在内存描述符 struct mm_struct 结构中的 mmap 中,正是这个 mmap 串联起了整个虚拟内存空间中的虚拟内存区域struct rb_node vm_rb;//每个 VMA 区域都是红黑树中的一个节点,通过 struct vm_area_struct 结构中的 vm_rb 将自己连接到红黑树中//红黑树中的根节点存储在内存描述符 struct mm_struct 中的 mm_rb 中struct list_head anon_vma_chain; struct mm_struct *vm_mm;	/* The address space we belong to. *///在每个虚拟内存区域 VMA 中又通过 struct vm_area_struct 中的 vm_mm 指针指向了所属的虚拟内存空间 mm_structunsigned long vm_start;     /* Our start address within vm_mm. */unsigned long vm_end;       /* The first byte after our end addresswithin vm_mm. *//** Access permissions of this VMA.*/pgprot_t vm_page_prot;unsigned long vm_flags; struct anon_vma *anon_vma;  /* Serialized by page_table_lock */struct file * vm_file;      /* File we map to (can be NULL). */unsigned long vm_pgoff;     /* Offset (within vm_file) in PAGE_SIZEunits */ void * vm_private_data;     /* was vm_pte (shared mem) *//* Function pointers to deal with this struct. */const struct vm_operations_struct *vm_ops;
}

六、程序编译后的二进制文件如何映射到虚拟内存空间中

进程的虚拟内存空间 mm_struct 以及这些虚拟内存区域 vm_area_struct 是如何被创建并初始化的呢?

我们写的程序代码编译之后会生成一个 ELF 格式的二进制文件,这个二进制文件中包含了程序运行时所需要的元信息,比如程序的机器码,程序中的全局变量以及静态变量等。

这个 ELF 格式的二进制文件中的布局和我们前边讲的虚拟内存空间中的布局类似,也是一段一段的,每一段包含了不同的元数据。

磁盘文件中的段我们叫做 Section,内存中的段我们叫做 Segment,也就是内存区域。

磁盘文件中的这些 Section 会在进程运行之前加载到内存中并映射到内存中的 Segment。通常是多个 Section 映射到一个 Segment。

这些 ELF 格式的二进制文件中的 Section 是如何加载并映射进虚拟内存空间的呢?

内核中完成这个映射过程的函数是 load_elf_binary ,这个函数的作用很大,加载内核的是它,启动第一个用户态进程 init 的是它,fork 完了以后,调用 exec 运行一个二进制程序的也是它。当 exec 运行一个二进制程序的时候,除了解析 ELF 的格式之外,另外一个重要的事情就是建立上述提到的内存映射。

static int load_elf_binary(struct linux_binprm *bprm)
{...... 省略 ........// 设置虚拟内存空间中的内存映射区域起始地址 mmap_basesetup_new_exec(bprm);...... 省略 ........// 创建并初始化栈对应的 vm_area_struct 结构。// 设置 mm->start_stack 就是栈的起始地址也就是栈底,并将 mm->arg_start 是指向栈底的。retval = setup_arg_pages(bprm, randomize_stack_top(STACK_TOP),executable_stack);...... 省略 ........// 将二进制文件中的代码部分映射到虚拟内存空间中error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt,elf_prot, elf_flags, total_size);...... 省略 ........// 创建并初始化堆对应的的 vm_area_struct 结构// 设置 current->mm->start_brk = current->mm->brk,设置堆的起始地址 start_brk,结束地址 brk。 起初两者相等表示堆是空的retval = set_brk(elf_bss, elf_brk, bss_prot);...... 省略 ........// 将进程依赖的动态链接库 .so 文件映射到虚拟内存空间中的内存映射区域elf_entry = load_elf_interp(&loc->interp_elf_ex,interpreter,&interp_map_addr,load_bias, interp_elf_phdata);...... 省略 ........// 初始化内存描述符 mm_structcurrent->mm->end_code = end_code;current->mm->start_code = start_code;current->mm->start_data = start_data;current->mm->end_data = end_data;current->mm->start_stack = bprm->p;...... 省略 ........
}

七、内核虚拟内存空间

不同进程之间的虚拟内存空间是相互隔离的,彼此之间相互独立,相互感知不到其他进程的存在。使得进程以为自己拥有所有的内存资源。

内核态虚拟内存空间是所有进程共享的,不同进程进入内核态之后看到的虚拟内存空间全部是一样的。

以32位系统下内核空间为例,介绍内核空间的几大块

1.直接映射区

内核态虚拟内存空间的前 896M 区域是直接映射到物理内存中的前 896M 区域中的,直接映射区中的映射关系是一比一映射。映射关系是固定的不会改变

物理内存的直接映射区前 16M 专门让内核用来为 DMA 分配内存,这块 16M 大小的内存区域我们称之为 ZONE_DMA。剩下的部分也就是从 16M 到 896M(不包含 896M)这段区域,我们称之为 ZONE_NORMAL

2.动态映射区

本例中我们的物理内存假设为 4G,高端内存区域为 4G - 896M = 3200M,那么这块 3200M 大小的 ZONE_HIGHMEM 区域该如何映射到内核虚拟内存空间中呢?

由于内核虚拟内存空间中的前 896M 虚拟内存已经被直接映射区所占用,而在 32 体系结构下内核虚拟内存空间总共也就 1G 的大小,这样一来内核剩余可用的虚拟内存空间就变为了 1G - 896M = 128M。

显然物理内存中 3200M 大小的 ZONE_HIGHMEM 区域无法继续通过直接映射的方式映射到这 128M 大小的虚拟内存空间中。

物理内存 896M 以上的区域被内核划分为 ZONE_HIGHMEM 区域,我们称之为高端内存。

内核虚拟内存空间中的 3G + 896M 这块地址在内核中定义为 high_memory,high_memory 往上有一段 8M 大小的内存空洞。空洞范围为:high_memory 到 VMALLOC_START 。

接下来 VMALLOC_START 到 VMALLOC_END 之间的这块区域成为动态映射区。采用动态映射的方式映射物理内存中的高端内存。

3.永久映射区

在 PKMAP_BASE 到 FIXADDR_START 之间的这段空间称为永久映射区。在内核的这段虚拟地址空间中允许建立与物理高端内存的长期映射关系。比如内核通过 alloc_pages() 函数在物理内存的高端内存中申请获取到的物理内存页,这些物理内存页可以通过调用 kmap 映射到永久映射区中。

4.固定映射区

 内核虚拟内存空间中的下一个区域为固定映射区,区域范围为:FIXADDR_START 到 FIXADDR_TOP。

5.临时映射区

 7.1 32 位体系内核虚拟内存空间布局

7.2 64 位体系内核虚拟内存空间布局


八、参考

小林 coding

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

独立站怎么建设对seo好?

现如今市面上就有不少开源的建站程序可供挑选,哪怕你不懂技术,不懂代码,也能建自己的独立站,效果比不少所谓的用自己技术开发的站都要好,本身做一个网站不难,但你做网站的目的是什么?是为了在搜…

【代码随想录-数组】二分查找

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学习,不断总结,共同进步,活到老学到老导航 檀越剑指大厂系列:全面总结 jav…

JDWP原理分析与漏洞利用

JDWP(Java DEbugger Wire Protocol):即Java调试线协议,是一个为Java调试而设计的通讯交互协议,它定义了调试器和被调试程序之间传递的信息的格式。说白了就是JVM或者类JVM的虚拟机都支持一种协议,通过该协议,Debugger 端可以和 target VM 通信,可以获取目标 VM的包括类…

选择海外云手机需要考虑什么?

随着跨境电商行业的蓬勃发展,企业们纷纷寻找提升平台流量和广告投放效果的方法,这已成为业界的当务之急。传统的宣传模式在国内受到直播和链接带货等新兴方式的冲击,而在国外,类似的趋势也在悄然兴起,呈现出广阔的发展…

安全防御第三次作业

作业:拓扑图及要求如下图 注:server1是ftp服务器,server2是http服务器 lsw1: 其中g0/0/0口为trunk 实现 1,生产区在工作时间内可以访问服务器区,仅可以访问http服务器 验证: 2,办公…

RedisInsight详细安装教程

简介 RedisInsight 是一个直观高效的 Redis GUI 管理工具,它可以对 Redis 的内存、连接数、命中率以及正常运行时间进行监控,并且可以在界面上使用 CLI 和连接的 Redis 进行交互(RedisInsight 内置对 Redis 模块支持)。 RedisIn…

Mac M1 Parallels CentOS7.9 Deploy 禅道

禅道官网下载地址: https://www.zentao.net/download/max4.10-83276.html 一、官网下载 二、解压安装 将下载好的包传至CentOS7.9虚拟机 zhinian192 ~ % scp Downloads/ZenTaoPMS-max4.10-zbox_arm64.tar.gz root10.211.55.36:~ ZenTaoPMS-max4.10-zbox_arm64.tar.gz …

C#,入门教程(31)——预处理指令的基础知识与使用方法

上一篇: C#,入门教程(30)——扎好程序的笼子,错误处理 try catchhttps://blog.csdn.net/beijinghorn/article/details/124182386 Visual Studio、C#编译器以及C#语法所支持的预处理指令,绝对是天才设计。 编译程序的时候会发现&am…

计算机网络体系架构认知--网络协议栈

文章目录 一.计算机网络分层架构各协议层和计算机系统的联系从整体上理解计算机网络通信计算机网络通信的本质 二.Mac地址,IP地址和进程端口号三.局域网通信与跨局域网通信局域网通信跨局域网通信全球互联的通信脉络 四.网络编程概述 一.计算机网络分层架构 实现计算机长距离网…

STP生成树协议

生成树协议(spanning tree protocol) 是一种工作在OSI网络模型中第二层(数据链路层)的通信协议,是一种由交换机运行的,基本应用是防止交换机冗余链路产生的环路,用于确保以太网中无环路的逻辑拓扑结构,从而避免了广播风暴&#x…

什么是 Web3.0

什么是Web3.0 对于 Web3.0 的解释网上有很多,目前来说 Web3.0 是一个趋势,尚未有明确的定义。我们今天讨论下几个核心的点,就能很好的理解 Web3.0 要解决哪些问题 谁创造数据,这里的数据可以是一篇博客,一段视频&…

计算机网络——网络层(1)

计算机网络——网络层(1) 小程一言专栏链接: [link](http://t.csdnimg.cn/ZUTXU) 网络层:数据平面网络层概述核心功能协议总结 路由器工作原理路由器的工作步骤总结 网际协议IPv4主要特点不足IPv6主要特点现状 通用转发和SDN通用转发SDN(软件…

插入排序和希尔排序

. 个人主页:晓风飞 专栏:数据结构|Linux|C语言 路漫漫其修远兮,吾将上下而求索 文章目录 插入排序基本思想:代码实现; 希尔排序基本思想:在这里插入图片描述多组并排优化《数据结构(C语言版)》--- 严蔚敏希…

OpenCV笔记之图像处理中遮罩和掩模的关系

OpenCV笔记之图像处理中遮罩和掩模的关系 code review 文章目录 OpenCV笔记之图像处理中遮罩和掩模的关系1.遮罩详解遮罩的创建遮罩的应用遮罩的主要应用遮罩的类型如何创建遮罩遮罩在图像处理中的应用方式 2.遮罩和掩模的关系 1.遮罩详解 在图像处理中,遮罩&#…

6 时间序列(不同位置的装置如何建模): GRU+Embedding

很多算法比赛经常会遇到不同的物体产生同含义的时间序列信息,比如不同位置的时间序列信息,风力发电、充电桩用电。经常会遇到该如此场景,对所有数据做统一处理喂给模型,模型很难学到区分信息,因此设计如果对不同位置的…

Flume1.9基础学习

文章目录 一、Flume 入门概述1、概述2、Flume 基础架构2.1 Agent2.2 Source2.3 Sink2.4 Channel2.5 Event 3、Flume 安装部署3.1 安装地址3.2 安装部署 二、Flume 入门案例1、监控端口数据官方案例1.1 概述1.2 实现步骤 2、实时监控单个追加文件2.1 概述2.2 实现步骤 3、实时监…

大模型学习笔记一:大模型应用开发基础

文章目录 一、大模型一些概念介绍 一、大模型一些概念介绍 1)产品和大模型的区别(产品通过调用大模型来具备的能力) 2)AGI定义 概念:一切问题可以用AI解决 3)大模型通俗原理 根据上文,猜测下…

vue模拟聊天页面列表:滚动到底部,滚动到顶部触发加载更多

先看下效果&#xff1a; 代码&#xff1a; <template><div><div style"text-align: center"><button click"scrollTop">滚动到顶部</button><button click"scrollBottom">滚动到底部</button></d…

win10安装redis并配置加自启动(采用官方推荐unix子系统)

记录&#xff0c;为啥有msi安装包&#xff0c;还这么麻烦的用linux版本redis的安装方式&#xff0c;是因为从github上下载别人制作的msi报毒&#xff0c;还不止一处&#xff0c;这种链接数据库的东西&#xff0c;用别人加工过的&#xff0c;都报毒了还用就是傻逼了。 所以采用…

【计算机网络】协议,电路交换,分组交换

定义了在两个或多个通信实体之间交换的报文格式和次序,以及报文发送和/或接收一个报文或其他事件所采取的动作.网络边缘: 端系统 (因为处在因特网的边缘) 主机 端系统 客户 client服务器 server今天大部分服务器都属于大型数据中心(data center)接入网(access network) 指将端…