我在测试程序中观察到以下行为:
我正在malloc()
进行1 MB的操作,然后在free()
之后进行sleep(10)
。我做了五次。程序运行时,我正在观察top
中的内存消耗。
一旦free()
-d,我预计程序的虚拟内存(VIRT)消耗将减少1 MB。但实际上并非如此。它保持稳定。这种现象的解释是什么? malloc()
在分配内存时会做一些保留吗?
答案 0 :(得分:42)
一旦
free()
-d,我预计程序的虚拟内存(VIRT)消耗将减少1MB。
好吧,这不是C标准所保证的。它只是说,free()
内存一旦使用,就不应再访问它。
由内存管理器决定是将内存块实际返回到可用的内存池中还是留作以后的分配。
答案 1 :(得分:27)
C标准不会强制SocketException: OS Error: Operation timed out, errno = 60, address = IPfromMyMachine, port = 65353
和malloc
的实现者直接将内存返回给OS。因此,不同的C库实现将表现不同。他们中有些人可能会直接将其还给他人,有些则可能不会。实际上,根据分配大小和模式,相同的实现也将表现不同。
这种行为当然是有充分理由的:
在大多数情况下,如果实现决定保留它,则free
对您的内存不承担任何责任(假设它是一个好的实现)。迟早将其重新分配或返回给OS。因此,针对内存使用量的优化应基于您拥有free
-d而没有malloc
-d的数量。您必须担心的情况是,当您的分配模式/大小开始引起内存碎片时,这本身就是一个很大的话题。
但是,如果您在嵌入式系统上,并且可用内存量有限,并且您需要更多地控制何时/如何分配和释放内存,那么您需要直接从OS请求内存页并进行管理手动。
编辑:我没有解释为什么您不为释放的内存负责。 原因是,在现代OS上,分配的内存是虚拟的。这意味着,如果您在32位系统或10TB 64位系统上分配512MB,只要您不对该内存进行读写操作,它将不会为其保留任何物理空间。实际上,它只会为您从那个大块而不是整个块中触摸的页面保留物理内存。并且在“一段时间不使用该内存”之后,其内容将被复制到磁盘,并且底层物理内存将用于其他用途。
答案 2 :(得分:11)
这很大程度上取决于所使用的实际malloc实现。
在Linux下,有一个阈值(MMAP_THRESHOLD
)可以确定给定malloc()
请求的内存来自哪里。
如果请求的数量小于或等于MMAP_THRESHOLD
,则可以通过从所谓的“空闲列表”中获取请求来满足该请求(如果已经存储了free()
d个存储块)。否则,将增加程序的"break line"(即数据段的末尾),并且将通过此过程提供给程序的内存用于请求。
在free()
上,已释放的内存块被添加到空闲列表中。如果数据段的末尾有足够的可用内存,则再次移动折线(上面已提及)以缩小数据段,将多余的内存返回给操作系统。
如果请求的数量超过MMAP_THRESHOLD
,则操作系统会请求一个单独的内存块,并在free()
期间再次返回。
有关详细信息,另请参见https://linux.die.net/man/3/malloc。