程序员都应该了解:为什么要自定义内存malloc

更多互联网新鲜资讯、工作奇淫技巧关注原创【飞鱼在浪屿】(日更新)
程序员都应该了解:为什么要自定义内存malloc文章插图
本文为你解释下列问题:
【程序员都应该了解:为什么要自定义内存malloc】为什么实现自己的内存分配器?可以编写比操作系统更好的内存分配器吗?不应该只使用自带垃圾回收机制的语言吗?
为什么要自定义分配器?大约在2010年左右 , 当Chipmunk2D(二维实时刚体物理引擎)是新的(ish)时 , 它没有使用任何自定义分配器 。 过程中根据需要分配了临时数据 , 跟踪并在完成后将其释放 。 在开发它的时候 , 使用OS X , 进行了压力测试视频 , 其中有一台旧的Core 2 Duo笔记本电脑上实时有成千上万个碰撞对象 。 但是 , 在Windows XP上运行相同的代码并不是很好 。
如果有人建议使用自定义分配器 , 可能会对这个主意不屑一顾 , 因为查看OS X上的探查器数据采样告诉我 , 内存功能毕竟还不到CPU时间的1% 。 那为什么要努力改造内存分配器使得其更有效率呢?
这样说吧 , 将所有碰撞数据打包在一起以使其对缓存友好 。 所以要做的是保留各种类型的结构的内存池 。 如果需要一个碰撞对结构 , 可以从内存池里抓一个 。 如果池是空的 , 将首先在一个大块中再分配几千字节 。 对游戏伙伴者的数据做了类似的操作 , 但是由于只需要保存一个帧 , 因此可以一次将整个数据块释放回池中 。 这解决了Windows性能问题 , 并且局部实现也使其他平台获得了非常不错的性能提升!
如果你读到最后再回头来看 , 刚刚描述了Slab分配器和Zone分配器 。 :)
需要比malloc()更好的理由那到底malloc()给我们什么呢?

  • 访问几乎无限量的虚拟内存
  • 创建或释放任意大小的个人分配空间
  • 从任何线程安全透明地访问分配空间
这些都是很棒的功能 , 很难有合适的通用替代办法 。 另一方面 , 其中的许多程序和系统具有独特的内存要求 。 对于Chipmunk2D的碰撞系统 , 我需要的是完全不同的:
  • 内存位置
  • 可预测的性能
  • 简化的内存所有权
自定义分配器与性能有关 , 而垃圾回收与简化所有权有关 , 但是事实证明两者并不是矛盾的 。 在垃圾回收语言中使用一些自定义分配器技术可以提高性能 , 而在传统语言中使用它们可以带来许多与垃圾回收一样的好处 。
使用自定义分配器的更多原因也许使用通用分配器会浪费了很多时间来调试内存问题 。 仅使用哈希表和一组链接列表 , 就可以跟踪所有分配的历史记录 。 这使得在出现free错误 , 两次free错误和内存泄漏后很容易跟踪使用情况 。 使用围绕自定义分配的保护page , 可以检测到内存溢出 。 这样的技术可以很好地补充Valgrind或AddressSanitizer等外部工具 。 在简化的内存所有权 , 拥有有助于检测错误的工具以及在问题发生时进行调试的工具之间 , 可以高兴地说 , 多年来你不会花很多时间来调试内存问题 。 :)
普通分配器1)Slab Allocator
程序员都应该了解:为什么要自定义内存malloc文章插图
Chipmunk2D的碰撞对示例基本上是一个Slab分配器 。 这个方案是 , 分配器只需要记住已分配的大块内存(slab)的列表 , 然后将这些对象分成一些固定大小的小块内存 , 用于存储在空闲分配链接列表中的对象 。 诀窍是将分配节点本身用作链接列表节点 , 因此不必浪费任何额外的内存来进行跟踪 。 分配内存的速度与将节点推送或弹出到链表中的速度一样快 , 并且仅在现有Slab空间不足时才需要与操作系统进行对话 。 此外 , 所有内存都打包在一起 , 这有助于利用CPU cache缓存 。 另外 , 肯定会打包小而临时性的分配 , 并最大程度地减少主内存空间的碎片 。