我一开始以为是堆,但它似乎在不同的地方分配内存。radare2 将其标记为以下内容:
0x00007fb07dacd000 - 0x00007fb07dace000 - usr 4K s rw- unk2 unk2
既然不是堆,那我们把mmap
ped内存所在的段叫做什么?
我一开始以为是堆,但它似乎在不同的地方分配内存。radare2 将其标记为以下内容:
0x00007fb07dacd000 - 0x00007fb07dace000 - usr 4K s rw- unk2 unk2
既然不是堆,那我们把mmap
ped内存所在的段叫做什么?
我不能 100% 确定这是 U&L 问题还是SO问题。总的来说,我将它发布在 U&L 上,因为它与操作系统相关。
据我所知,Linux 将通过将共享库(.so 文件)映射为写时复制来加载共享库(.so 文件)。这样做的一个优点是,共享同一个大型库的多个进程都将共享相同的物理 RAM,用于该库的大部分内容。
Docker 不一定会发生这种情况,因为进程在基于“映像”的自己的“容器”中运行,并且每个映像都包含它自己的共享库副本。这是故意的。它允许程序附带它们自己的依赖项(库),这些依赖项可能与系统上已安装的库有很大不同。
因此,在 docker 主机上本地运行的程序不会与在 docker 容器中运行的程序共享相同的库内存,因为 docker 容器中的程序已映射到库的不同副本。
Docker 镜像是分层创建的。每一层都添加到较低的一层,有时会覆盖现有文件。并非每个文件都在每一层中更改。
Docker 允许您通过向旧图像添加新层来创建新图像。发生这种情况时,您最终会得到多个共享相同图层的图像。这些图像共享一些相同文件的相同副本。
Docker 将这些层分开保存,至少在运行时之前是这样。例如:从 Docker Hub 拉取图像,Docker 通过获取每个图像的组成层来获取图像。它只获取它还没有的层。
在创建或运行容器时,Docker 必须将这些层组装成一个单一的连贯文件系统。我不知道它是怎么做到的。它可能:
根据它的作用,源自同一层的文件可能是相同的副本,或者它们可能是文件系统上的完全相同的文件。
这最终会影响文件被多个进程映射到内存时发生的情况。
我想知道从两个不同的图像运行两个容器是否会为源自单个层的单个共享库共享相同的 RAM。
我正在阅读Linux 编程接口。
49.9 MAP_NORESERVE 和交换空间过度使用
一些应用程序创建大型(通常是私有匿名)映射,但只使用映射区域的一小部分。例如,某些类型的科学应用程序分配一个非常大的数组,但只对数组中几个相隔很远的元素(所谓的稀疏数组)进行操作。
如果内核总是为整个此类映射分配(或保留)足够的交换空间,那么可能会浪费大量的交换空间。相反,内核可以仅在实际需要时(即,当应用程序访问页面时)为映射的页面保留交换空间。这种方法称为惰性交换保留,其优点是应用程序使用的总虚拟内存可以超过 RAM 加上交换空间的总大小。
换句话说,惰性交换保留允许过度使用交换空间。只要所有进程不尝试访问其映射的整个范围,这就可以正常工作。...
据我所知,交换空间是磁盘中的一块空间,保留用于内存交换。当内存中的这些页面处于非活动状态时,它们会被交换到磁盘中的交换空间中。它就像内存/内存的二级缓存。
那么这个惰性交换预留机制到底是什么鬼?
让我用一个例子来说明我的困惑。
一些应用程序创建大型(通常是私有匿名)映射......
好的,然后假设我malloc
有一个大数组16384(4096*4)
字节(创建大型(通常是私有匿名)映射),并且只对数组中几个广泛分离的元素进行操作。
然后一些非活动页面被交换到交换空间,对吗?假设0-4095(4096B)
,8192-12287(4096B)
在内存中,所有其他非活动页面4096-8191(4096B)
,12288-16383(4096B)
被交换到交换空间中。
那么这句话是什么意思:
相反,内核可以仅在实际需要时(即,当应用程序访问页面时)为映射的页面保留交换空间。
如果不留在交换空间4096-8191(4096B)
中,这些非活动页面(和)还能留在哪里?文本似乎表明交换空间存在 3 级缓存。 12288-16383(4096B)
memory -> swap space (disk) -> ????
我有一个非常大的磁盘驱动器 (2TB),但不是很多 RAM (8GB)。我希望能够在我的磁盘文件系统上存在的一个大文件(~200GB)上运行一些大数据实验。我知道这在磁盘带宽方面会非常昂贵,但我不介意高 I/O 使用率。
如何将这个巨大的文件加载到 C++ 数组中,以便可以在我选择的位置对文件执行读写操作?mmap 是否适用于此目的?我应该使用哪些参数选项来执行此操作?我不想在运行程序的任何时候触发 OOM 杀手。
我知道 mmap 支持文件支持和匿名映射,但我不完全确定使用哪个。使用私有映射与共享映射之间怎么样?
我试图了解当mmap
系统调用已映射到内存的文件随后被其他进程写入时会发生什么。
我在“进程A”中对mmap
内存进行了保护。PROT_READ
如果我关闭进程 A 中的底层文件描述符,然后另一个进程写入该文件(不使用mmap
; 只是将 stdout 简单重定向到>
shell 中使用的文件),mmap
进程 A 的地址空间中的 ed 内存是否受影响? 鉴于这些页面是只读的,我希望它们不会改变。但是,在尝试解析映射的内存时,SIGBUS
由于无效的内存访问 ( ) ,进程 A 被信号终止。Non-existent physical address at address 0x[...]
我怀疑这是由其他进程写入支持文件引起的。设置MAP_PRIVATE
是否足以完全保护此内存免受其他进程的影响?
我知道 64 位 PC 使用的地址空间是[0,2^48)
,但是我可以使用 mmap 将文件映射到 2 48以上的地址吗?
我写了下面的代码,但发现映射的地址还在里面[0,2^48)
。
int
main(void) {
const char* name = "/tmp/file";
int fd = open(name, O_RDONLY);
if (fd < 0) {
perror("open");
exit(-1);
}
int pageSize = sysconf(_SC_PAGE_SIZE);
void* targetAddr = (void*)(0UL - pageSize);
char* str = mmap(targetAddr, pageSize, PROT_READ, MAP_SHARED, fd, 0);
if (str == MAP_FAILED) {
perror("mmap");
exit(-1);
}
printf("addr: %p\n", str);
return 0;
}
样本输出:addr: 0x7fc761f6f000
甚至可以将某些文件映射到 2 48以上的地址mmap
吗?
如果没有,我该如何使用“未使用的”bit48-bit63?
我只是好奇如何利用地址的高位。
操作系统:Ubuntu16.04
内存大小:4GB