Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/145.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/58.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么在分配更大的空间时堆地址的增长方向相反?_C++_C_Memory_Operating System - Fatal编程技术网

C++ 为什么在分配更大的空间时堆地址的增长方向相反?

C++ 为什么在分配更大的空间时堆地址的增长方向相反?,c++,c,memory,operating-system,C++,C,Memory,Operating System,我在堆地址增长上做了一些实验,发生了一些有趣的事情。 (操作系统:CentOS,) 但我不明白,为什么会这样?谢谢 这是我首先做的: double *ptr[1000]; for (int i=0;i<1000;i++){ ptr[i] = new double[**10000**]; cout << ptr[i] << endl; } 然后我将10000改为20000: double *ptr[1000]; for (int i=0;i<1

我在堆地址增长上做了一些实验,发生了一些有趣的事情。 (操作系统:CentOS,)

但我不明白,为什么会这样?谢谢

这是我首先做的:

double *ptr[1000];
for (int i=0;i<1000;i++){
    ptr[i] = new double[**10000**];
    cout << ptr[i] << endl;
}
然后我将10000改为20000:

double *ptr[1000];
for (int i=0;i<1000;i++){
    ptr[i] = new double[**20000**];
    cout << ptr[i] << endl;
}

在这里你不会得到一个很好的答案,因为新函数可以选择它想要分配内存的任何方法。我猜想,这里的算法将池分解成小的和大的分配池,并且大的分配池向下生长,以便它们可以在中间相遇(以便不浪费任何空间)。

< P>不同的环境/实现使用不同的策略分配内存,因此没有一个正确的规则。然而,一种常见的模式是对小对象和大对象使用不同的分配策略

通常,一个运行时会有多个不同大小对象的堆,这些堆针对不同的使用模式进行了优化。例如,小对象往往会被频繁分配并快速删除,而大对象往往很少创建且寿命较长

如果您对所有内容都使用一个堆,那么一些小对象将很快被添加到整个内存空间中,留下许多中等大小的块可用,但大对象只需要很少或根本不需要大的块。这被称为内存碎片,即使名义上你的应用程序有大量可用内存,也会导致分配失败

使用不同堆的另一个原因是对不同的对象大小使用不同的使用情况跟踪方法。例如,对于大型对象,实现可能会从操作系统请求一个新的内存块,对于小型对象,使用几个较小的操作系统内存块,并由C运行时堆管理器处理子分配。对于大型对象非常有效的内存使用情况跟踪机制对于小型对象可能非常昂贵,因为用于跟踪使用情况的内存占每个对象实际使用内存的很大一部分


在您的情况下,我猜想运行时是在内存空间的开始处(自下而上)分配小对象,在接近结尾处(自上而下)分配大对象,以避免碎片。

在UNIX上,分配器使用sbrk(2)和mmap(2)从操作系统获取内存。sbrk返回的地址定义良好,但mmap返回的地址是“任何可用的”。在Windows上,分配器使用类似于mmap的VirtualAlloc()。

实现可以自由混合使用不同的分配方案。在C++中,有成千上万个相对较小的对象是正常的,因此,它可以对库的内存分配例程有意义,以确保它们打包得很好,并且非常轻量级。您对10000个双字节的分配就是这样的:它们相隔80016字节-对于10000个8字节的变量,它们相隔80000字节,只有16字节的填充。节点特别指出,大小与二的幂无关,而当分配20000倍时,它们每次递减163840字节。。。奇怪的是,正好是10*2^14。这就意味着,以前的分配是从一个堆中得到满足的,它是由C++分配<代码>新< /Cuff>函数支持的有效的小对象分配,而后者则跨越了Stand,并且可能被发送到 MalOC/<代码>,用于来自不同堆的内存,有更多的浪费。

你很幸运,10000双和20000双的大小恰好位于一个称为MMAP_阈值的临界阈值的两侧

默认情况下,MMAP_阈值为128KB。因此,80KB(即10000倍)的mem alloc请求通过堆提供服务,而160KB(20000倍)的mem alloc请求通过匿名内存映射(通过mmap sys调用)提供服务。(请注意,对大型mem alloc使用mem映射可能会因其不同的底层mem alloc处理机制而招致额外的惩罚。您可能需要调整MMAP_阈值以实现应用程序的最佳性能。)

在:

通常,malloc()从堆中分配内存,并使用sbrk(2)根据需要调整堆的大小。当分配大于MMAP_阈值字节的内存块时,glibc malloc()实现使用MMAP(2)将内存分配为私有匿名映射。默认情况下,MMAP_阈值为128 kB,但可以使用mallopt(3)进行调整。使用mmap(2)执行的分配不受RLIMIT_数据资源限制的影响(请参阅getrlimit(2))

double *ptr[1000];
for (int i=0;i<1000;i++){
    ptr[i] = new double[**20000**];
    cout << ptr[i] << endl;
}
....
....
0x7f69c4d8a010
0x7f69c4d62010
0x7f69c4d3a010
0x7f69c4d12010
0x7f69c4cea010
0x7f69c4cc2010
0x7f69c4c9a010
0x7f69c4c72010
0x7f69c4c4a010
0x7f69c4c22010
0x7f69c4bfa010
0x7f69c4bd2010
0x7f69c4baa010
0x7f69c4b82010