一些分配器是懒惰的吗?

2024-10-17 08:47:00
admin
原创
213
摘要:问题描述:我在 Linux 中编写了一个 C 程序,它分配内存,循环运行它,而 TOP 没有显示任何内存消耗。然后我对该内存做了一些操作,TOP 确实显示了内存消耗。当我 malloc 时,我是否真的“获得内存”,或者是否存在“懒惰”的内存管理,只有当我使用它时才给我内存?(还有一个选项是,TOP 仅在我使用...

问题描述:

我在 Linux 中编写了一个 C 程序,它分配内存,循环运行它,而 TOP 没有显示任何内存消耗。

然后我对该内存做了一些操作,TOP 确实显示了内存消耗。

当我 malloc 时,我是否真的“获得内存”,或者是否存在“懒惰”的内存管理,只有当我使用它时才给我内存?

(还有一个选项是,TOP 仅在我使用时才知道内存消耗,所以我不确定这一点。)

谢谢


解决方案 1:

在 Linux 上,malloc 使用 sbrk() 或 mmap() 请求内存 - 无论哪种方式,您的地址空间都会立即扩展,但 Linux 直到第一次写入相关页面时才会分配实际的物理内存页面。您可以在 VIRT 列中看到地址空间扩展,而实际的物理内存使用情况则在 RES 中看到。

解决方案 2:

这开始有点偏离主题(然后我会把它和你的问题联系起来),但发生的事情类似于在 Linux 中 fork 进程时发生的事情。fork 时有一种称为写时复制的机制,它只在内存被写入时复制新进程的内存空间。这样,如果 fork 进程立即执行一个新程序,那么你就节省了复制原始程序内存的开销。

回到你的问题,这个想法是相似的。正如其他人指出的那样,请求内存会立即获得虚拟内存空间,但实际页面仅在写入时才分配。

这样做的目的是什么?它基本上使 mallocing 内存成为一个或多或少恒定时间操作 Big O(1),而不是 Big O(n) 操作(类似于 linux 调度程序将其工作分散开来而不是将其集中在一个大块中的方式)。

为了证明我的意思我做了以下实验:

rbarnes@rbarnes-desktop:~/test_code$ time ./bigmalloc 

real    0m0.005s
user    0m0.000s
sys 0m0.004s
rbarnes@rbarnes-desktop:~/test_code$ time ./deadbeef 

real    0m0.558s
user    0m0.000s
sys 0m0.492s
rbarnes@rbarnes-desktop:~/test_code$ time ./justwrites 

real    0m0.006s
user    0m0.000s
sys 0m0.008s

bigmalloc 程序分配了 2000 万个 int,但并未对它们执行任何操作。deadbeef 将一个 int 写入每个页面,导致写入次数为 19531 次,而 justwrites 分配了 19531 个 int 并将其清零。如您所见,deadbeef 的执行时间比 bigmalloc 长约 100 倍,比 justwrites 长约 50 倍。

#include <stdlib.h>    

int main(int argc, char **argv) {

int *big = malloc(sizeof(int)*20000000); // allocate 80 million bytes

return 0;

}

#include <stdlib.h>    

int main(int argc, char **argv) {

int *big = malloc(sizeof(int)*20000000); // allocate 80 million bytes

// immediately write to each page to simulate all at once allocation

// assuming 4k page size on 32bit machine

for ( int* end = big + 20000000; big < end; big+=1024 ) *big = 0xDEADBEEF ;    

return 0;

}

#include <stdlib.h>

int main(int argc, char **argv) {

int *big = calloc(sizeof(int),19531); // number of writes

return 0;
}

解决方案 3:

是的,除非您触摸它,否则内存不会映射到您的内存空间中。 mallocing 内存只会设置分页表,以便他们知道当您在分配的内存中出现页面错误时,应该映射内存。

解决方案 4:

您是否在使用编译器优化?也许优化器已经删除了分配,因为您没有使用分配的资源?

解决方案 5:

该功能称为过度使用- 内核通过增加数据段大小“承诺”为您提供内存,但不为其分配物理内存。当您触摸该新空间中的地址时,进程会页面错误进入内核,然后内核会尝试将物理页面映射到该地址。

解决方案 6:

是的,请注意VirtualAlloc标志,

MEM_RESERVE
MEM_COMMIT

呵呵,但是对于Linux或任何POSIX/BSD/SVR#系统,vfork() 已经存在很长时间了,并且提供了类似的功能。

vfork() 函数与 fork() 的唯一区别在于,子进程可以与调用进程(父进程)共享代码和数据。如果 vfork() 被误用,这将大大加快克隆活动的速度,但会危及父进程的完整性。

除作为立即调用 exec 系列函数或 _exit() 的前奏之外,不建议将 vfork() 用于任何目的。

vfork() 函数可用于创建新进程,而无需完全复制旧进程的地址空间。如果分叉进程只是调用 exec,则不会使用通过 fork() 从父进程复制到子进程的数据空间。这在分页环境中效率特别低,因此 vfork() 特别有用。根据父进程数据空间的大小,vfork() 可以比 fork() 显著提高性能。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用