操作系统--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.mzph.cn/news/649014.shtml

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

相关文章

Android App开发基础(3)——App的设计规范

3 App的设计规范 本节介绍了App工程的源码设计规范,首先App将看得见的界面设计与看不见的代码逻辑区分开,然后利用XML标记描绘应用界面,同时使用Java代码书写程序逻辑,从而形成App前后端分离的设计规约,有利于提高App集…

快毕业了,同学纪念册如何制作出高级感

​快毕业了,这是一个充满回忆和感慨的时刻。同学们都想制作一本高级感的同学纪念册,留住这段美好的时光。但是自己着手制作的纪念册太丑,那不出手怎么办?那你就问对人了,我给大家演示几个步骤,需要的可以学…

【java】常见的面试问题

目录 一、异常 1、 throw 和 throws 的区别? 2、 final、finally、finalize 有什么区别? 3、try-catch-finally 中哪个部分可以省略? 4、try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗&#…

瀑布流布局 (初版)

瀑布流布局 文章目录 瀑布流布局前言1. 背景2. 点⬇️🔗去体验效果如下图所示: 一、初版waterfall布局和问题暴露?1.效果图如下:2.暴露问题如下图所示:第一张问题图:第二张问题图: 3.HTML代码如…

有效的字母异位词

42. 有效的字母异位词https://leetcode.cn/problems/valid-anagram/ 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。 注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。 示例 1: 输入: s …

8.6 代理设计模式

文章目录 一、代理模式(Proxy Pattern)概述二、代理模式和观察者设计模式三、模式结构四、协作角色五、实现策略六、相关模式七、示例八、应用 一、代理模式(Proxy Pattern)概述 代理模式是一种设计模式,它通过引入一个…

智能体AI Agent的极速入门:从ReAct到AutoGPT、QwenAgent、XAgent

前言 如这两天在微博上所说,除了已经在七月官网上线的AIGC模特生成系统外,我正在并行带多个项目组 第二项目组,论文审稿GPT第2版的效果已经超过了GPT4,详见《七月论文审稿GPT第2版:用一万多条paper-review数据集微调…

Vue-38、Vue中插件使用

1、新建plugins.js文件 2、可以在plugins.js 定义全局过滤器 定义全局指令 定义混入 给vue原型上添加一个方法 export default {install(Vue){console.log("install",Vue);//全局过滤器Vue.filter(mySlice,function (value) {return value.slice(0,4)});//定义全局…

遇到这3种接口测试问题,其实,你可以这么办~

作为整个软件项目的必经环节,软件测试是不可缺少的“查漏补缺”环节。而作为软件测试中的重要一环——接口测试,几乎串联了整个项目所有的输入和输出环节。 前几年,我在做后端测试时,接触最多的正是接口测试。基于此,…

操作系统-进程通信(共享存储 消息传递 管道通信 读写管道的条件)

文章目录 什么是进程通信为什么进程通信需要操作系统支持共享存储消息传递直接通信方式间接通信方式 管道通信小结注意 什么是进程通信 分享吃瓜文涉及到了进程通信 进程通信需要操作系统支持 为什么进程通信需要操作系统支持 进程不能访问非本进程的空间 当进程P和Q需要…

幻兽帕鲁服务器数据备份

搭建幻兽帕鲁个人服务器,最近不少用户碰到内存不足、游戏坏档之类的问题。做好定时备份,才能轻松快速恢复游戏进度 这里讲一下如何定时将服务器数据备份到腾讯云轻量对象存储服务,以及如何在有需要的时候进行数据恢复。服务器中间的数据迁移…

数据结构(顺序表)

文章目录 一、线性表1、线性表1.1、线性表的定义1.2、线性表的操作 2、顺序表2.1、顺序表的实现--静态分配2.2、顺序表的实现--动态分配2.2、顺序表的特点 3、顺序表的基本操作3.1、插入操作3.2、删除操作3.3、查找操作3.2、按位查找3.2、按值查找 一、线性表 1、线性表 1.1、…

Git 删除已经 Push 到远程多余的文件

例如要删除 data/log 文件 1. 在当前项目下打开终端 2. 查看有哪些文件夹 dir 3. 预览将要删除的文件(如果不清楚该目录下是否存在不应该删除的文件) git rm -r -n --cached 文件/文件夹名称 加上 -n 这个参数,执行命令时,是不会…

Numpy应用-股价分析实战

股价统计分析 数据样本 股价常用指标 极差 越高说明波动越明显 股价近期最高价的最大值和最小值的差价 成交量加权平均价格 英文名VWAP(Volume-Weighted Average Price,成交量加权平均价格)是一个非常重要的经济学量,代表着金融…

苹果Find My市场需求火爆,伦茨科技ST17H6x芯片助力客户量产

苹果发布AirTag发布以来,大家都更加注重物品的防丢,苹果的 Find My 就可以查找 iPhone、Mac、AirPods、Apple Watch,如今的Find My已经不单单可以查找苹果的设备,随着第三方设备的加入,将丰富Find My Network的版图。产…

Google Chrome RCE漏洞 CVE-2020-6507 和 CVE-2024-0517 流程分析

本文深入研究了两个在 Google Chrome 的 V8 JavaScript 引擎中发现的漏洞,分别是 CVE-2020-6507 和 CVE-2024-0517。这两个漏洞都涉及 V8 引擎的堆损坏问题,允许远程代码执行。通过EXP HTML部分的内存操作、垃圾回收等流程方式实施利用攻击。 CVE-2020-…

操作符详解(上)

目录 操作符的分类 二进制和进制转换 2进制转10进制 10进制转2进制数字 2进制转8进制 2进制转16进制 原码、反码、补码 移位操作符 左移操作符 右移操作符 位操作符:&、|、^、~ 单目操作符 逗号表达式 操作符的分类 • 算术操作符: …

【C++干货铺】 RAII实现智能指针

个人主页点击直达:小白不是程序媛 C系列专栏:C干货铺 代码仓库:Gitee 目录 为什么需要智能指针? 内存泄漏 什么是内存泄漏,内存泄露的危害 内存泄漏的分类 堆内存泄漏(Heap leak) 系统资…

CMG GPP 0.05°全球区域2000~2019年月数据分享

各位同学们好,今天分享的是CMG GPP 0.05全球区域2000~2019年月数据。您可以私信或评论。 一、数据简介 准确估算陆地植被的初级生产总值(GPP)对于了解全球碳循环和预测未来气候变化至关重要。目前有多种基于不同方法的 GPP 产品&#xff0c…

ORM-08-EclipseLink 入门介绍

拓展阅读 The jdbc pool for java.(java 手写 jdbc 数据库连接池实现) The simple mybatis.(手写简易版 mybatis) 1. EclipseLink概述 本章介绍了EclipseLink及其关键特性:包括在EclipseLink中的组件、元数据、应用程序架构、映射和API。 本…