她与晚风 发表于 2023-4-2 01:31:45

操作系统内零头

操作系统内存管理中的分页技术,内零头指的是每个进程的最后一条指令未占满页框的那段空间吗?
所以一个进程只有一块内零头吗?

isdkz 发表于 2023-4-2 01:44:55

是的,你的理解是正确的。在操作系统内存管理中,分页技术是一种将虚拟内存划分为固定大小的单位(通常称为“页”或“页面”)的方法。在分页系统中,当一个进程的地址空间被映射到物理内存时,其内存需求可能并不是页面大小的整数倍。因此,每个进程的最后一个页面可能未被完全填满。这段未被占满的内存空间被称为“内零头”。

每个进程确实只有一块内零头,因为内零头总是位于进程地址空间的最后一个页面。在大多数情况下,内零头并不会导致严重的内存浪费,但是如果有很多进程并且每个进程的内零头很大,那么这些内零头加起来可能会占用一定的内存空间。为了解决这个问题,某些内存管理算法采用了诸如内存碎片整理和合并的方法来减少内零头产生的内存浪费。

dolly_yos2 发表于 2023-4-2 09:49:36

最后一个页面可能未被完全填满的逻辑是正确的,但进程的虚拟内存空间不一定是连续的,可能被划分为多个连续的空间段,每一连续的虚拟内存段最后一个页面都可能出现未被充分利用的情况

她与晚风 发表于 2023-4-2 12:18:45

isdkz 发表于 2023-4-2 01:44
是的,你的理解是正确的。在操作系统内存管理中,分页技术是一种将虚拟内存划分为固定大小的单位(通常称为 ...

那有没有一条语句被分到了两个页这种情况呢?

isdkz 发表于 2023-4-2 12:20:37

她与晚风 发表于 2023-4-2 12:18
那有没有一条语句被分到了两个页这种情况呢?

在现代计算机体系结构和操作系统的内存管理中,一条指令(或者说一条语句)不会被分到两个页面。原因如下:


[*]指令对齐:处理器会对指令进行对齐,这意味着指令会从某个固定的地址开始。这些地址通常是指令字长的整数倍。对齐有助于提高处理器的内存访问性能。

[*]页面边界:在分页系统中,页面具有固定的大小和边界。当进程的指令和数据被加载到内存时,操作系统会确保指令和数据在页面边界内。


由于这些原因,一条指令不会跨越两个页面。当然,指令可能在一个页面的末尾,而下一条指令恰好在下一个页面的开头,但这种情况下,指令本身不会被分到两个页面。

她与晚风 发表于 2023-4-2 12:35:28

isdkz 发表于 2023-4-2 12:20
在现代计算机体系结构和操作系统的内存管理中,一条指令(或者说一条语句)不会被分到两个页面。原因如下 ...

蟹蟹大佬{:9_228:}

dolly_yos2 发表于 2023-4-2 13:43:55

isdkz 发表于 2023-4-2 12:20
在现代计算机体系结构和操作系统的内存管理中,一条指令(或者说一条语句)不会被分到两个页面。原因如下 ...

似乎能构造反例
我在我的系统上查看了页面大小为4096字节$ getconf PAGESIZE
4096
现在编写一个很简单的 C 语言程序#include <unistd.h>
#include <stdio.h>
int main(){
    printf("pid=%d\n", getpid());
    int a = 0;
    a = a + 1;
    // 这里省略了410行 a = a + 1;
    sleep(-1);
    return 0;
}
然后用 clang 将其编译得到可执行文件,再用 objdump 反汇编得到指令序列,可以看到在代码段接近结尾的地方有这样三行:1ffb:       89 45 f8                mov    %eax,-0x8(%rbp)
1ffe:       bf ff ff ff ff          mov    $0xffffffff,%edi
2003:       e8 48 f0 ff ff          call   1050 <sleep@plt>
4096字节用16进制表示是0x1000,显然这里的这条 mov 指令跨越了边界
接下来实际运行验证。运行这个程序会输出其进程号帮助验证,且会长时间睡眠来保持不退出。用输出的内存号查看内存映射(部分信息已经被隐藏):$ cat /proc/44021/maps
561b4067f000-561b40680000 r--p 00000000 --:-- -a.out
561b40680000-561b40682000 r-xp 00001000 --:-- -a.out
561b40682000-561b40683000 r--p 00003000 --:-- -a.out
561b40683000-561b40684000 r--p 00003000 --:-- -a.out
561b40684000-561b40685000 rw-p 00004000 --:-- -a.out
561b41f85000-561b41fa6000 rw-p 00000000 --:-- 0
其中代码段是有执行权限的561b40680000-561b40682000,可见恰好占用两页
接下来将这两页的信息读取出来:$ sudo dd if=/proc/44021/mem of=memdump1 bs=4096 count=1 skip=23114024576
$ sudo dd if=/proc/44021/mem of=memdump2 bs=4096 count=1 skip=23114024577
最后检查读取出的内容:$ hexdump -s 4090 -C memdump1
01 89 45 f8 bf ff
$ hexdump -n 8 -C memdump2
ff ff ff e8 48 f0 ff ff
和之前的反汇编信息对比就可以发现那条 mov 指令恰好出现在第一页的末尾和第二页的开始,跨越了两页
页: [1]
查看完整版本: 操作系统内零头