数组中的内存是如何分配的?

有4个不同的案例。

a)全局变量和静态局部变量。对于这些,数组通常构建在可执行程序的文件中(该文件通常被分成几个部分-一个用于代码,一个用于初始化的只读数据,一个用于初始化的数据,一个用于“初始化为零”的/uninitialized数据)。大多数情况下,如果数组被初始化(例如int foo[44] = { 1, 2, 3 };),那么它将被放入正常的读/写数据部分(.data),如果它没有被初始化(例如int foo[44];),它将被放入“初始化为零”的/uninitialized数据部分(.bss),以减小文件的大小。在(例如)中分配空间.data段与在可执行文件的.text段中为代码分配空间没有太大区别。在这种情况下,不能释放内存。

b)局部变量(在函数内部,如void foo(void) { int bar[44]; })。在这种情况下,编译器通常会在堆栈上为它创建空间(并且它不会被“初始化为零”)。如果它被显式初始化,那么编译器将生成代码来初始化它,要么使用指令(如果数组很小),要么通过从数据段中的隐藏副本复制数据(其中隐藏副本的分配方式与全局变量的分配方式相同)。在这种情况下,内存不能被显式释放,但将被隐式释放(如果/当您从函数返回时)。

c)线程本地存储(例如__thread int foo[])。在这种情况下,编译器通常在线程本地存储中分配空间;如果数组被初始化,它还会在数据段中创建一个隐藏副本(其中,隐藏副本的分配方式与全局变量的分配方式相同)。在这种情况下,不能释放内存。

d)动态分配的数组(例如int *myPointer = malloc(sizeof(int) * 44);)。对于这些,编译器不会在任何地方分配空间(运行时库分配空间)。这是唯一可以显式释放内存的情况(例如free(myPointer);)。

注意1:上面的很多(我通常使用的地方)都依赖于实现,编译器可能会做一些非常不同的事情;要么是因为“做不同的事情”对编译器的输出更有意义,要么是因为编译器可以适当地进行优化。

注2:遗憾的是,大多数编译器不能正确优化。当数组未被修改时,即使您使用const,也很难让他们使用.rodata部分。对于有用于初始化的隐藏数组的情况,很难让它们分析内容并找到更复杂的模式(对于int foo[] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; }这样的简单模式,它们可能/将很难做到这一点)。如果你有一个像int hugeArray[12345678] = {4, 5, 6}这样的全局数组,他们不会把数组放在.bss部分并初始化它来减少文件大小,即使这样做是微不足道的,等等)。


康佳43英寸4K高清电视1299元
我的媳妇是女王相关推荐