沈天真
作者沈天真·2021-08-02 00:24
售前支持·IPS

内存那些事儿---- tcmalloc on Power-I

字数 2309阅读 934评论 0赞 0

系列文章,欢迎阅读

内存那些事儿----基础知识I

https://www.talkwithtrend.com/Article/255113

内存那些事儿----基础知识II

https://www.talkwithtrend.com/Article/255115

内存那些事儿----内存带宽

https://www.talkwithtrend.com/Article/255545

内存那些事儿----HBM和GPU算力

https://www.talkwithtrend.com/Article/255551

内存那些事儿----Huge Page on Power-I

https://www.talkwithtrend.com/Article/256329

内存那些事儿---- Huge Page on Power-II

https://www.talkwithtrend.com/Article/256331

内存分配器

对于大多数开发者而言,系统的内存分配就是一个黑盒子,就是几个API的调用,最常见的API应该就是 malloc() 和 free() 和realloc() ,它们是glibc库中提供的内存分配器。但是当你实际深入进去时,会发现内存分配器的世界比你想象的要热闹的多。有操作系统层面的内存分配器(Memory Allocator),有应用程序层面的,有为实时系统设计的,有为服务程序设计的。但是所有的内存分配器的目的却是一样的,平衡内存分配的性能和提高内存使用的效率。一个好的内存分配器,能够同时提高这两方面的性能。就像很多人说的,苹果手机或者苹果电脑总是可以用更少的内存运行的更加流畅,虽然不能说完全是内存分配器的功劳,但是和 IOS / MacOS 的内存分配管理肯定是密不可分的。

需要牢记的一点,内存分配器操作的并不是物理的内存,而是虚拟内存。对这一点不清楚的,可以先了解Linux的虚拟内存(virtual memory)管理机制。

一个好的内存分配器,通常需要均衡下列多个目标:

ü 最大化兼容性

一个分配器应该可以和其他程序插件式兼容;特别是它应该遵守ANSI/POSIX惯例。

ü 最大化可移植性

尽可能少的依赖于系统依赖的特性(像是系统调用),同时仍然要为只在某些系统上才存在的有用特性提供选择性的支持;在对齐和寻址规则上为所有已知的系统限制保持一致。

ü 最小化空间

分配器不应该浪费空间:它应该尽可能少的从系统获取内存,并且以最小化分段(连续内存块中不被程序使用的“洞”)的方式维护内存。

ü 最小化时间

malloc(),free()和realloc()例程在平均情况下应该尽可能的快。

ü 最大化可调整性

可选的特性和行为应该可以被用户静态的(通过类似于#define的东西)或动态的(通过mallopt这样的控制命令)控制。

ü 最大化局部性

分配的内存快通常在临近的地方被使用。这在程序执行期间帮助最小化页面和cache丢失。

ü 最大化错误探测

把一个一般用途分配器也当作一般用途内存错误检测工具(像是Purify)使用看上去是不可能的。尽管如此,分配器应该提供一些方法探测由于改写内存,多次释放等等这样的错误导致的内存混乱。

ü 最小化异常性

一个使用默认设置的分配器应该可以在一个很大程度上依赖于动态分配的宽阔的真实负载下正常工作--窗口工具包,GUI应用程序,编译器,解释器,开发工具,网络(包)密集型程序,图像密集型包,网络浏览器,字符串处理应用程序,等等。

下图是常见内存分配器,以及它们在某个测试中的表现。

内存碎片

内存碎片即“碎片的内存”,它分为外部碎片和内部碎片,内存碎片描述一个系统中所有不可用的空闲内存,这些碎片之所以不能被使用,是因为负责动态分配内存的分配算法使得这些空闲的内存无法使用,这一问题的发生,原因在于这些空闲内存小且以不连续方式出现在不同的位置。因此这个问题的或大或小取决于内存管理算法的实现上。

外部碎片

外部碎片指的是还没有被分配出去(不属于任何进程),但由于太小了无法分配给申请内存空间的新进程的内存空闲区域。频繁的分配与回收物理页面会导致大量的、连续且小的页面块夹杂在已分配的页面中间,就会产生外部碎片。假设有一块一共有100个单位的连续空闲内存空间,范围是0~99。如果你从中申请一块内存,如10个单位,那么申请出来的内存块就为0~9区间。这时候你继续申请一块内存,比如说5个单位大,第二块得到的内存块就应该为10~14区间。如果你把第一块内存块释放,然后再申请一块大于10个单位的内存块,比如说20个单位。因为刚被释放的内存块不能满足新的请求,所以只能从15开始分配出20个单位的内存块。现在整个内存空间的状态是0~9空闲,10~14被占用,15~24被占用,25~99空闲。其中0~9就是一个内存碎片了。如果10~14一直被占用,而以后申请的空间都大于10个单位,那么0~9就永远用不上了,变成外部碎片。

内部碎片

内部碎片就是已经被分配出去(能明确指出属于哪个进程)却不能被利用的内存空间。因为所有的内存分配必须起始于可被 4、8 或 16 整除(视处理器体系结构而定)的地址或者因为MMU的分页机制的限制,决定内存分配算法仅能把预定大小的内存块分配给客户。假设当某个客户请求一个43字节的内存块时,因为没有适合大小的内存,所以它可能会获得 44字节、48字节等稍大一点的字节,因此由所需大小四舍五入而产生的多余空间就叫内部碎片。

至此,介绍了内存分配器的基本概念以及内存碎片的产生原因。后续将介绍新的内存分配器是如何尽量减少内存碎片的产生,提高内存利用率和吞吐量。

如果觉得我的文章对您有用,请点赞。您的支持将鼓励我继续创作!

0

添加新评论0 条评论

Ctrl+Enter 发表

作者其他文章

相关文章

相关问题

相关资料

X社区推广