当前位置: 首页> 科技> 能源 > 页面设计升级_浙江最新通知今天_西安百度关键词优化_企业网站制作模板

页面设计升级_浙江最新通知今天_西安百度关键词优化_企业网站制作模板

时间:2025/7/11 8:18:53来源:https://blog.csdn.net/weixin_39775340/article/details/147193912 浏览次数:0次
页面设计升级_浙江最新通知今天_西安百度关键词优化_企业网站制作模板

0.内存空间架构

1.用户空间

        在 Linux 系统中,应用程序通过 malloc() 申请内存,并通过 free() 释放内存时,底层的内存管理是由 glibc(GNU C Library)中的内存分配器实现的。glibc 的内存分配器负责与操作系统的内核交互,以高效地管理堆内存的分配和释放。

以下是 malloc() 和 free() 在 glibc 中的工作原理及其实现细节:

1.1 glibc 内存分配器概述


        glibc 使用了一种高效的用户态内存管理机制,称为 ptmalloc(Pthreads malloc)。ptmalloc 是基于早期的 dlmalloc(Doug Lea's malloc)改进而来,主要目标是支持多线程环境下的高效内存分配。

(1) 主要特点

  • 多线程支持: ptmalloc 为每个线程维护独立的堆(arena),减少多线程间的锁争用。
  • 内存池化: 小块内存会被分配到内存池中,避免频繁调用系统调用。
  • 内存复用: 释放的内存不会立即归还给操作系统,而是保留在内存池中供后续重用。
  • 大块内存优化: 大块内存直接使用 mmap() 分配,避免对堆的影响。

         其它内存分配器:还由谷歌公司的tcmalloc分配器与freeBSD 的jemalloc

1.2 malloc() 的工作原理


       malloc() 是 glibc 提供的用户态函数,用于动态分配内存。其底层实现会根据请求的内存大小选择不同的策略。

(1) 小块内存分配(< 128KB 或其他阈值)

堆扩展:

  • 如果堆中有足够的空闲内存,则直接从堆中分配。
  • 如果堆中没有足够的空闲内存,则调用 brk() 系统调用来扩展堆。

内存池管理:

  • glibc 使用一种称为 bins 的数据结构来管理小块内存。
  • 不同大小的内存块会被存储在不同的 bins 中,便于快速查找和分配。

(2) 大块内存分配(>= 128KB 或其他阈值)

匿名映射:
对于大块内存,malloc() 会直接调用 mmap() 系统调用创建一个独立的匿名映射区域。
这样可以避免对堆的影响,并且释放时可以直接调用 munmap() 归还给操作系统。

(3) 底层实现

malloc() 的核心实现位于 glibc 源码中的 malloc.c 文件。
它依赖于内部的数据结构(如 malloc_chunk)来管理内存块。

1.3 free() 的工作原理
     

      free() 是 glibc 提供的用户态函数,用于释放由 malloc() 分配的内存。它的实现会根据内存块的大小和分配方式采取不同的策略。

(1) 小块内存释放

内存回收:

  • 释放的小块内存不会立即归还给操作系统,而是被放回到 glibc 的内存池中。
  • glibc 会将释放的内存块插入到对应的 bin 中,以便后续重用。

合并空闲块:

  • 如果相邻的内存块也是空闲的,glibc 会尝试将它们合并为更大的空闲块,以减少碎片化。


(2) 大块内存释放

解除映射:

  • 对于通过 mmap() 分配的大块内存,free() 会直接调用 munmap() 系统调用将其归还给操作系统。

立即释放:

  • 大块内存不会保留在内存池中,而是立即释放。

(3) 堆收缩

如果堆中有大量连续的空闲内存,glibc 可能会调用 brk() 系统调用来收缩堆,将未使用的内存归还给操作系统。
不过,这种行为通常受到一定的限制,因为频繁调整堆顶可能会影响性能。

1.4 glibc 内存分配器的核心数据结构

    glibc 的内存分配器依赖于一些核心数据结构来管理内存块和空闲列表。

(1) malloc_chunk

  • 每个分配的内存块都由一个 malloc_chunk 结构体描述。
  • 它包含以下信息:
  • 内存块的大小。
  • 是否已使用。
  • 指向前一个和后一个内存块的指针(用于链表管理)。
struct malloc_chunk {size_t prev_size;  // 前一个块的大小(如果前一个块是空闲的)size_t size;       // 当前块的大小(包括元数据)struct malloc_chunk *fd;  // 指向下一个空闲块struct malloc_chunk *bk;  // 指向前一个空闲块
};

(2) bins

glibc 使用多个 bins 来管理不同大小的空闲内存块。
Fast bins:

  • 用于管理非常小的内存块(如 16 字节、32 字节等)。
  • Fast bins 不会合并相邻的空闲块,以提高分配速度。

Unsorted bin:

  • 用于暂存刚刚释放的内存块,稍后再分类到合适的 bin 中。

Small bins 和 Large bins:

  • Small bins 用于管理固定大小的内存块。
  • Large bins 用于管理较大范围的内存块。


以下是一个简单的示例,展示 malloc() 和 free() 的使用:

#include <stdio.h>
#include <stdlib.h>int main() {// 分配小块内存int *small_mem = (int *)malloc(1024);  // 1 KBif (small_mem == NULL) {perror("malloc failed");return -1;}printf("Small memory allocated at: %p\n", small_mem);// 分配大块内存void *large_mem = malloc(1024 * 1024);  // 1 MBif (large_mem == NULL) {perror("malloc failed");return -1;}printf("Large memory allocated at: %p\n", large_mem);// 释放内存free(small_mem);free(large_mem);return 0;
}

2.内核空间

2.1 内核空间的基本功能

     虚拟内存管理

  • 虚拟内存管理负责从进程的虚拟地址空间分配虚拟页。
  • sys_brk 用来扩大或收缩堆。
  • sys_mmap 用来在内存映射区域分配虚拟页。
  • sys_munmap 用来释放虚拟页。

内核使用延迟分配物理内存的策略:

  • 当进程请求分配内存时(如通过 brk() 或 mmap()),内核仅分配虚拟页,而不立即分配物理页。
  • 只有当进程实际访问这些虚拟页时,才会触发缺页异常(Page Fault),内核才会分配物理页并更新页表。
  • 进程第一次访问虚拟页的时候,触发页错误异常。
  • 页错误异常处理程序从页分配器申请物理页,在进程的页表中把虚拟页映射到物理页。

页分配器

  • 页分配器负责分配物理页,目前使用的页分配器是伙伴分配器。
  • 内核空间提供把页划分成小内存块分配的块分配器,提供分配内存的接口 kmalloc() 和释放内存的函数 kfree()。

  支持三种分配器:slab 分配器、slub 分配器和 slob 分配器。
 

在内核初始化的过程中,页分配器还没有准备好,需要使用临时的引导内存分配器分配内存。 

2.2内核空间的扩展功能

不连续页分配器

  • 提供分配内存的接口 vmalloc 和释放内存的接口 vfree。
  • 在Linux内核中,vmalloc函数用于分配不连续的物理内存页面,并将它们映射到虚拟地址空间中的一个连续区域。这与直接使用kmalloc或__get_free_pages等接口不同,后者要求分配的物理页面必须是连续的
  • 在内存碎片化的时候,申请连续物理页的成功率很低。
  • 可以申请不连续的物理页,映射到连续的虚拟页,即虚拟地址连续但物理地址不连续。
  • 每个处理器内存分配器用来为每个处理器变量分配内存。

连续内存分配器

  • 用来给驱动程序预留一段连续的内存。
  • 当驱动程序不用的时候,可以给进程使用。
  • 当驱动程序需要使用的时候,把进程占用的内存通过回收或迁移的方式让出来,给驱动程序使用。

内存控制组

  • 用来控制进程占用的内存资源。

3.硬件层面

内存管理单元 (MMU, Memory Management Unit)

  • 处理器包含一个称为内存管理单元 (MMU) 的部件。
  • MMU 负责将虚拟地址转换成物理地址。这种转换对于操作系统来说非常重要,因为它允许每个进程拥有自己的独立地址空间,增强了系统的安全性和稳定性。
  •    保护机制:通过地址转换过程,MMU 可以实现对内存访问的权限控制。例如,它能够阻止一个进程直接访问另一个进程的内存区域,或者限制对特定内存页的读写权限。

页表缓存 (TLB, Translation Lookaside Buffer)

  • 内存管理单元包含一个页表缓存 (TLB) 部件。
  • TLB 保存最近使用过的页表映射,避免每次把虚拟地址转换为物理地址时都需要查询内存中的页表。
  • 加速地址转换:每次进行虚拟地址到物理地址的转换都需要查询内存中的页表,这会消耗一定的时间。为了提高效率,MMU 使用 TLB 来缓存最近使用过的地址映射。当需要再次访问相同的虚拟地址时,可以直接从 TLB 中获取对应的物理地址,而无需再访问主存中的页表。
  • 性能提升:由于 TLB 的存在,大多数情况下地址转换可以非常快速地完成,从而显著提升了系统性能。然而,如果所需的地址映射不在 TLB 中(称为 TLB Miss),则仍然需要访问页表来完成地址转换,并且该映射会被添加到 TLB 中以便将来使用

缓存

  • 为了解决处理器的执行速度和内存访问速度不匹配的问题,在处理器和内存之间增加缓存。
  • 缓存通常分为一级缓存 (L1 Cache) 和二级缓存 (L2 Cache)。
  • 为了支持并行地取指令和取数据,一级缓存分为数据缓存 (Data Cache) 和指令缓存 (Instruction Cache)。
关键字:页面设计升级_浙江最新通知今天_西安百度关键词优化_企业网站制作模板

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: