目的:为了让物理内存扩充成更大的逻辑内存,从而让程序获得更多的可用内存。一般为物理内存的1.5--3倍。
内存管理单元(MMU):管理着地址空间和物理内存的转换,其中的页表(Page table)存储着页(程序地址空间)和页框(物理内存空间)的映射表。
虚拟地址:分成两个部分,一部分存储页面号,一部分存储偏移量。
分页:虚拟内存采用的是分页技术,也就是将地址空间划分成固定大小的页,每一页再与内存进行映射。
分段::把每个表分成段,一个段构成一个独立的地址空间。每个段的长度可以不同,并且可以动态增长。
段页式:程序的地址空间划分成多个拥有独立地址空间的段,每个段上的地址空间划分成大小相同的页。这样既拥有分段系统的共享和保护,又拥有分页系统的虚拟内存功能。
分页和分段的区别:
1.对程序员的透明性:分页透明,但是分段需要程序员显式划分每个段。
2.地址空间的维度:分页是一维地址空间,分段是二维的。
3.大小是否可以改变:页的大小不可变,段的大小可以动态改变。
4.出现的原因:分页主要用于实现虚拟内存,从而获得更大的地址空间;分段主要是为了使程序和数据可以被划分为逻辑上独立的地址空间并且有助于共享和保护。
页面置换算法
最近最久未使用(LRU, Least Recently Used):LRU 将最近最久未使用的页面换出。
- 实现原理:为了实现 LRU,需要在内存中维护一个所有页面的链表。当一个页面被访问时,将这个页面移到链表表头。这样就能保证链表表尾的页面是最近最久未访问的。
因为每次访问都需要更新链表,因此这种方式实现的 LRU 代价很高。 -
说明它在 Redis 等作为缓存置换算法。
当实际内存超出 maxmemory 时,Redis 提供了几种可选策略 (maxmemory-policy) 来让用户自己决定淘汰哪些key。总结如下:
当 Redis 执行写操作时,发现内存超出 maxmemory,就会执行一次 LRU 淘汰算法。
Redis 使用的是一种近似 LRU 算法:
1、key增加最近访问时间戳字段
2、选取一定数量的key(默认5,server.maxmemory_samples进行配置),比较最近访问时间。按照LRU算法淘汰key。
注意:maxmemory_samples的值越大,Redis的近似LRU算法就越接近于严格LRU算法(队列结构重排,批量非热点数据缓存垃圾),但是相应消耗也变高,对性能有一定影响,样本值默认为5。
静态链接和动态链接
1. 编译系统
- 预处理阶段:处理以 # 开头的预处理命令;
- 编译阶段:翻译成汇编文件;
- 汇编阶段:将汇编文件翻译成可重定位目标文件;
- 链接阶段:将可重定位目标文件和 printf.o 等单独预编译好的目标文件进行合并,得到最终的可执行目标文件。
2. 静态链接
以一组可重定位目标文件为输入,生成一个完全链接的可执行目标文件作为输出。链接器主要完成以下两个任务:
- 符号解析:每个符号对应于一个函数、一个全局变量或一个静态变量,符号解析的目的是将每个符号引用与一个符号定义关联起来。
- 重定位:链接器通过把每个符号定义与一个内存位置关联起来,然后修改所有对这些符号的引用,使得它们指向这个内存位置。
3. 动态链接
静态库有以下两个问题:
- 当静态库更新时那么整个程序都要重新进行链接;
- 对于 printf 这种标准函数库,如果每个程序都要有代码,这会极大浪费资源。
共享库是为了解决静态库的这两个问题而设计的,在 Linux 系统中通常用 .so 后缀来表示,Windows 系统上它们被称为 DLL。它具有以下特点:
- 在给定的文件系统中一个库只有一个文件,所有引用该库的可执行目标文件都共享这个文件,它不会被复制到引用它的可执行文件中;
- 在内存中,一个共享库的 .text 节(已编译程序的机器代码)的一个副本可以被不同的正在运行的进程共享。
参考:https://blog.csdn.net/Daybreak1209/article/details/82840930