malloc和BSS之间是否存在任何限制或位置差异?
(为了回答这个问题,请忽略全局变量的利弊。) 全局变量是否与动态分配的内存位于同一内存空间中 例如,通常情况下,如果我想在内存中有一个大的多兆字节的数据结构,那么我需要malloc()这个数量,并从那里使用一个结构指针 我的问题是,这和仅仅将大型结构定义为全局结构在内存上有什么区别吗?我知道未初始化的全局变量在对象BSS中定义了它们的大小,但实际上不会占用对象文件中的空间,所以从某种意义上说,它们是在运行时分配的。但是,根据BSS的定义,对全局的大小有任何限制吗?他们是不是以malloc以外的方式分配的?这个答案适用于 静态对象没有分配给malloc和BSS之间是否存在任何限制或位置差异?,c,allocation,linux,x86-64,C,Allocation,Linux,X86 64,(为了回答这个问题,请忽略全局变量的利弊。) 全局变量是否与动态分配的内存位于同一内存空间中 例如,通常情况下,如果我想在内存中有一个大的多兆字节的数据结构,那么我需要malloc()这个数量,并从那里使用一个结构指针 我的问题是,这和仅仅将大型结构定义为全局结构在内存上有什么区别吗?我知道未初始化的全局变量在对象BSS中定义了它们的大小,但实际上不会占用对象文件中的空间,所以从某种意义上说,它们是在运行时分配的。但是,根据BSS的定义,对全局的大小有任何限制吗?他们是不是以malloc以外的方
malloc
(当然,您不能尝试释放它们)。当二进制文件exec
ed时,内核会为它们分配内存,同时还会分配程序的其余代码和数据。这通常称为“加载时”,而不是“运行时”,因为它发生在程序的任何代码实际执行之前。唯一的区别是分配给.bss
的内存中没有填充从二进制文件加载的数据。与程序的其余部分一样,它通常是按需分页的,因此(归零)物理内存只有在实际读取或写入空间时才会分配,以后可能会交换到磁盘。它或多或少相当于一个匿名的mmap
(我在这里使用“static”一词是指存储持续时间,而不是范围,它同样适用于C中的全局变量和static
变量。对于位置无关的代码,这两个变量在内存位置上存在一些差异,我将不详细介绍,但它不会实质性地改变下面的信息。)
我假设您知道malloc
通常是如何工作的,以及它是如何从操作系统获取内存的(通过sbrk
或匿名mmap
,通常后者用于大型对象),所以我不会对此进行描述
您可能会遇到的主要区别是,在默认编译器设置下,静态数据(包括bss)限制在2GB左右。Linux编译器工具链默认使用;所有代码和静态数据都是使用32位有符号RIP相对位移来访问的,因此任何两个这样的地址彼此之间的距离必须在2GB以内,因此实际上该限制适用于所有代码和静态数据的总大小。如果超过此限制,程序将无法编译或链接。(事实上,在一些测试中,如果您足够幸运地将一个对象放在数据末尾,则可能有一个对象比这个大,但这不太可能在实际程序中实现。)
您可以通过在编译时选择“中”或“大”代码模型来避免此限制,以便使用64位绝对地址,但折衷是它们会导致代码更大,效率更低,可能会影响整个程序。因此,除非您有非常特殊的原因想要静态地分配大型对象,否则动态地分配它可能会更好
对于非常大的分配,如果可移植性不是必需的,您可能更愿意直接使用匿名mmap
,而不是malloc
。这使您可以更好地控制何时将内存返回操作系统(使用munmap
),还可以利用mprotect
、madvise
、大页面等功能,对MMU和分页机制进行更细粒度的控制
然而,总的来说,记忆就是记忆,不管它是如何获得的。这个答案适用于
静态对象没有分配给malloc
(当然,您不能尝试释放它们)。当二进制文件exec
ed时,内核会为它们分配内存,同时还会分配程序的其余代码和数据。这通常称为“加载时”,而不是“运行时”,因为它发生在程序的任何代码实际执行之前。唯一的区别是分配给.bss
的内存中没有填充从二进制文件加载的数据。与程序的其余部分一样,它通常是按需分页的,因此(归零)物理内存只有在实际读取或写入空间时才会分配,以后可能会交换到磁盘。它或多或少相当于一个匿名的mmap
(我在这里使用“static”一词是指存储持续时间,而不是范围,它同样适用于C中的全局变量和static
变量。对于位置无关的代码,这两个变量在内存位置上存在一些差异,我将不详细介绍,但它不会实质性地改变下面的信息。)
我假设您知道malloc
通常是如何工作的,以及它是如何从操作系统获取内存的(通过sbrk
或匿名mmap
,通常后者用于大型对象),所以我不会对此进行描述
您可能会遇到的主要区别是,在默认编译器设置下,静态数据(包括bss)限制在2GB左右。Linux编译器工具链默认使用;所有代码和静态数据都是使用32位有符号RIP相对位移来访问的,因此任何两个这样的地址彼此之间的距离必须在2GB以内,因此实际上该限制适用于所有代码和静态数据的总大小。如果超过此限制,程序将无法编译或链接。(事实上,在一些测试中,如果您足够幸运地将一个对象放在数据末尾,则可能有一个对象比这个大,但这不太可能在实际程序中实现。)
您可以通过在编译时选择“中等”或“大型”代码模型来避免此限制,因此