c - 为什么 brk(void *end_data_segment) 的参数不向上舍入到下一页边界?
问题描述
从Linux 编程接口:
int brk(void * end_data_segment );
系统调用将
brk()
程序中断设置为由 指定的位置end_data_segment
。由于虚拟内存是以页面为单位分配的,end_data_segment
因此有效地向上舍入到下一个页面边界。
所以对于这个演示:
#include <stdio.h>
#include <unistd.h>
int
main(int argc, char *argv[])
{
long int page_size = sysconf(_SC_PAGESIZE);
printf("My page size: %ld\n", page_size);
void* c1 = sbrk(0);
printf("program break address: %p\n", c1);
printf("sizeof char: %lu\n", sizeof(char));
c1 = (void*) ((char*) c1 + 1);
printf("c1: %p\n", c1);
brk(c1);
void* c2 = sbrk(0);
printf("program break address: %p\n", c2);
}
输出:
My page size: 4096
program break address: 0x55b0bc104000
sizeof char: 1
c1: 0x55b0bc104001
program break address: 0x55b0bc104001
我希望新的程序中断地址是:0x55b0bc104000 + 0x1000(4096 in HEX) == 0x55b0bc105000
为什么我没有得到0x55b0bc105000
,而是0x55b0bc104001
?
解决方案
将其视为两种可能性:
end_data_segment
与页面边界对齐;并确保虚拟地址空间底层区域的大小与end_data_segment
值完全匹配不要将 对齐
end_data_segment
到页面边界;并确保虚拟地址空间底层区域的大小与页面大小对齐(向上舍入)
对于第一种可能性,便携式软件(不知道页面大小将是多少)可以(例如)将页面增加end_data_segment
1/8 并分别执行 8 次,而不是最终得到一个额外的页面(结果你自然会期望)它最终会多出 8 页(比它想要的多 7 页,比预期的多 7 页)。更差; 软件可以减少end_data_segment
不到一页的大小,它什么也不做(将四舍五入到原始值);这也可以多次执行,导致软件试图摆脱但仍然存在的大面积区域。当然这些可以组合 - 软件可以增加end_data_segment
1 个字节然后减少end_data_segment
在循环中间减少一个字节,导致意外的内存(空间)泄漏,当人们期望它不会浪费任何东西时,它可能会迅速吞噬所有可用的虚拟地址空间。当然,软件可以通过在各处添加(非标准/不可移植)修复来明确解决所有问题,但这将非常难看。
第二种可能性(不对齐end_data_segment
)更直观、更方便且不易出错。
推荐阅读
- javascript - 使用 getEntry() 帮助程序到达 Contentful 的 API 时出现问题:未从已找到条目的承诺中返回任何内容
- mongodb - 将 CSV 文件导入 MongoDB 时如何防止更改 UUID?
- javascript - 通过复选框更新Javascript进度条?
- sql - 在最后一个斜线后获得 5 个字符
- javascript - 在嵌套的 Promise 中捕获所有块
- docker - Docker 灯重定向 https
- excel - 在ms excel中计算整行中连续值序列的数量
- excel - 如何使用来自不同列的值在 Excel 的 XY 散点图中添加不同的标记?
- typescript - 如何使用 Jest 和 TypeScript 正确存根/模拟 AWS SecretManager
- asp.net-mvc - 使用 Blazor 和实体框架时如何避免服务定位器模式?