这些电话中的哪一个平均更快?我听说mmap对于较小的分配来说速度更快,但我还没有听到过比较.任何有关这些表现的信息都会很好.
为什么不alloca检查它是否可以分配内存?
来自man 3 alloca:
如果分配导致堆栈溢出,则程序行为未定义....如果无法扩展堆栈帧,则没有错误指示.
为什么alloca不能/不能检查它是否可以分配更多内存?
我理解的方式是alloca在堆栈上分配内存时在堆栈上(s)brk分配内存.来自https://en.wikipedia.org/wiki/Data_segment#Heap:
堆区域由malloc,calloc,realloc和free管理,可以使用brk和sbrk系统调用来调整其大小
来自man 3 alloca:
alloca()函数在调用者的堆栈帧中分配空间的大小字节.
并且堆栈和堆在收敛方向上增长,如此Wikipedia图中所示:
(上图来自Dougimed的Wikimedia Commons,发布于CC BY-SA 3.0)
现在,这两个alloca并(s)brk返回一个指向新分配内存的开始,这意味着它们必须知道哪里栈/堆结束当前时刻.的确,来自man 2 sbrk:
以增量0调用sbrk()可用于查找程序中断的当前位置.
因此,他们理解它,检查是否alloca可以分配所需的内存,实质上归结为检查堆栈的当前末端和堆的当前末尾之间是否有足够的空间.如果在堆栈上分配所需的内存会使堆栈到达堆,则分配失败; 否则,它会成功.
那么,为什么不能使用这样的代码来检查是否alloca可以分配内存?
void *safe_alloca(size_t size)
{
if(alloca(0) - sbrk(0) < size) {
errno = ENOMEM;
return (void *)-1;
} else {
return alloca(size);
}
}
Run Code Online (Sandbox Code Playgroud)
这对我来说更加困惑,因为显然(s)brk可以做这样的检查.来自man 2 …
自从我被介绍到 以来C,我就被告知C动态内存分配是使用家族中的函数完成的malloc。我还了解到,动态分配的内存malloc是在进程的堆部分分配的。
各种操作系统教科书都说这malloc涉及系统调用(虽然并不总是但有时)来将堆上的结构分配给进程。现在假设malloc返回指向堆上分配的字节块的指针,为什么它需要系统调用。函数的激活记录放置在进程的堆栈部分中,并且由于“堆栈部分”已经是进程虚拟地址空间的一部分,所以激活记录的压入和弹出、堆栈指针的操作,只需从虚拟地址空间的最高可能地址。它甚至不需要系统调用。
现在基于同样的理由,由于“堆部分”也是进程虚拟地址空间的一部分,为什么需要系统调用来在该部分中分配字节块。像这样的例程malloc可以自行处理“空闲”列表和“已分配”列表。它需要知道的只是“数据部分”的结尾。某些文本说系统调用对于“将内存附加到进程以进行动态内存分配”是必要的,但是如果malloc在“堆部分”上分配内存,为什么需要在 期间将内存附加到进程malloc?可以简单地取自过程中已经一部分的部分。
在阅读 Kernighan 和 Ritchie 的《C 编程语言》[2e] 文本时,我发现了他们对该malloc函数的实现 [第 8.7 节第 185-189 页]。作者说:
malloc根据需要调用操作系统获取更多内存。
这就是操作系统文本所说的,但与我上面的想法相反(如果malloc在堆上分配空间)。
由于向系统请求内存是一项相对昂贵的操作,因此作者不会在每次调用 时都这样做,因此他们创建了一个至少请求单位的malloc函数;这个较大的块根据需要被切碎。而基本的空闲列表管理是由.morecoreNALLOCfree
但问题是作者使用sbrk()向操作系统请求内存morecore。现在维基百科说:
brk和是 Unix 和类 Unix 操作系统中使用的基本内存管理系统调用,用于控制分配给进程数据段sbrk的内存量。
在哪里
数据段(通常表示为.data)是目标文件或程序的相应地址空间的一部分,其中包含初始化的静态变量,即全局变量和静态局部变量。
我猜这不是“堆部分”。[数据部分是上图中从下数第二部分,而堆是从下数第三部分。]
我完全困惑了。我想知道到底发生了什么以及这两个概念如何正确?请通过将分散的碎片连接在一起来帮助我理解这个概念......
它似乎对sbrk的功能没有影响,但在sbrk()的文档中它说它需要一个intptr_t参数.
当将int类型作为参数传递时,它可以工作(或者至少似乎工作).
这是常规C.
我正在编写自己的函数,malloc并free在C中编写作业.我需要利用C sbrk()包装器功能.根据我的理解sbrk(),程序的数据空间增加了作为参数传递的字节数,并指向程序中断的位置.
如果我有以下代码段:
#define BLOCK_SIZE 20
int x;
x = (int)sbrk(BLOCK_SIZE + 4);
我得到编译器错误warning: cast from pointer to integer of different size.为什么这样,无论如何我可以将指向的地址sbrk()转换为int?
我正在尝试使用sbrk系统调用来请求一个内存页面并将该页面分成小块,但我的代码总是会遇到一些无效的内存:
void sbrkBlocks() {
int *b = sbrk(0);
if(sbrk(sysconf(_SC_PAGESIZE)) == (void *)-1) {
printf("sbrk failed\n");
return NULL;
}
void *bound =b + sysconf(_SC_PAGESIZE);
while (b + 16 <=bound) {
*b = 1;
b+= 16;
}
}
Run Code Online (Sandbox Code Playgroud)
就像我得到sbrk(0)的那样0x804d000,绑定之后sbrk(one_page_size)会是0x8055000,但是代码将会出现分段错误0x804e000.
我试图了解它是如何sbrk工作的.
这是我的小代码:
int main()
{
printf("end of the break : %p\n", sbrk(0));
printf("end of the break : %p\n", sbrk(10));
printf("new end of the break : %p\n\n", sbrk(0));
}
Run Code Online (Sandbox Code Playgroud)
这输出:
Run Code Online (Sandbox Code Playgroud)end of break : 0xaa6000 end of break : 0xac7000 new end of the break : 0xac700a
为什么前2个地址0xac7000 - 0xaa6000 = 21000而不是10?
在使用 glibc 时,我尝试使用sbrk使用负参数来减少数据段,并发现了一个最奇怪的行为。
\n我首先使用malloc,然后free使用它,然后使用 减少数据段sbrk,然后malloc再次使用与第一个相同的大小。
问题是,如果malloc大小(两个malloc大小相同)足够小(32k,或八个 4k 页),那么一切都可以正常工作。但是当我增加一点malloc- free-malloc大小(到九个 4k 页)时,我会得到核心转储。更奇怪的是,当我将大小提高malloc到超过mmap阈值(128k)时,我会得到调整中止行为。
C代码:
\n#define _GNU_SOURCE 1\n#include <stdio.h>\n#include <malloc.h>\n#include <unistd.h>\n\n// set MMAP_ALLOC_SIZE to 8 4k-pages it will work, \n// set it to 9 4k-pages it raises a \'segmentation fault (core dumped)\'\n// set it to 33 4k-pages it raises a \'break adjusted to free malloc space\' …Run Code Online (Sandbox Code Playgroud)