使用new、malloc等动态内存分配的时间复杂度是多少?我对内存分配器的实现知之甚少,但我认为答案取决于具体的实现方式。因此,请就一些较常见的情况/实现方式回答。
编辑: 我模糊地记得听说堆内存分配在最坏情况下没有上限,但我真正感兴趣的是平均/典型情况。
使用new、malloc等动态内存分配的时间复杂度是多少?我对内存分配器的实现知之甚少,但我认为答案取决于具体的实现方式。因此,请就一些较常见的情况/实现方式回答。
编辑: 我模糊地记得听说堆内存分配在最坏情况下没有上限,但我真正感兴趣的是平均/典型情况。
在处理 O 表示法时,你需要意识到的一件事是理解 n 是非常重要的。如果 n 与你能控制的某些内容有关(例如:你想要排序的列表中的元素数量),那么就有必要仔细看一下。
在大多数堆的实现中,n 是管理器处理的连续内存块的数量。这明显不是客户端通常可以控制的内容。客户端真正可以控制的唯一的 n 是她想要的内存块的大小。通常,这与分配器花费的时间无关。一个大的 n 可以像一个小的 n 一样快速分配,或者可能需要更长的时间,或者甚至可能无法服务。所有这些都可能因其他客户端之前的分配和释放方式而改变相同的 n。所以,除非你正在实现一个堆,否则正确的答案是它是非确定性的。
这就是为什么硬实时程序员尝试避免动态分配(启动后)的原因。
仅有两点需要注意:
TLSF 是O(1)的,因为它没有一个循环;并且可以管理高达2Gb的内存。 虽然这真的很难相信,但只需查看代码即可。
“最佳适配”策略(寻找最紧密的块)并不是实现小碎片化的最合适方法。 证明这一点远非易事,事实上尚未得到正式证明,但有许多证据表明这个方向是正确的。(很好的研究课题)。
看一下典型分配器的工作方式。
Bump-the-pointer分配器以的速度运行,而且这只是一个小小的'1'。
对于一个隔离存储分配器,分配k个字节意味着“从List(n)返回第一个块”,其中List(n)是n个字节的块列表,其中n >= k。它可能发现List(n)为空,因此必须将下一个列表(List(2n))的块分割,使得产生的两个块都是n字节,并放在List(n ),这种影响可能会波及所有可用大小,导致复杂度为O(ns),其中ns是可用不同尺寸的数量,ns = log(N),其中N 是可用的最大块大小,所以即使如此,也非常小。 在大多数情况下,特别是在分配和释放了一些块之后,复杂度是O(1)。
malloc()
返回的指针,否则这不起作用。移动东西是内核所做的事情。在早期没有MMU的计算机系统上,有时会这样做。旧版Mac / OS可以在68k处理器上使用代码执行此操作,当您的块足够小(代码少于64kb)时,因为它可以使用PC访问所有功能。 - Alexis Wilke