heiyeluren / xmm

XMM is a high performance third party memory manager for Go environments that is not affected by Gc and guarantees high performance. XMM是一个在Go语言环境中完全自主实现的第三方内存管理库,不依赖于Go本身的任何内存管理能力,纯自主实现能够应对各种场景下大小内存的 分配/释放 工作,能自主构建高性能的 链表/树/哈希表等各类数据结构,能良好完美的逃逸掉Go内置的GC机制,是构建高性能程序基础设施。
Apache License 2.0
1.12k stars 123 forks source link

是否有对比实验证明这个库在某种tradeoff的情况下比golang自带的好?好多少? #21

Open bronze1man opened 2 years ago

bronze1man commented 2 years ago

请给我一个我会引入这个库的一个具体理由。

heiyeluren commented 2 years ago

感谢 @bronze1man 提问,问题提的都非常好,一一给您解答。

  1. 内存管理均衡性问题:

    从设计机制上面来说,XMM和go内置的gc机制没有太本质区别,都是从用户态通过系统调用mmap的方式从内核申请一大块内存进行管理,go内置内存管理和XMM在这个设计上是基本一样的,go的内存管理和XMM底层都是从tcmalloc中学习的设计思想,所以在常态使用中(不会gc,元素很少)中使用go内置内存管理和XMM都是没有太大区别,只是XMM个人可控性更强一些。

  2. 关于XMM的gc和Go内置gc的对比:

    a. 关于gc的问题,本质就是最终内存回收的策略不同,决定性能不同。

    b. go的内存回收是主动式和被动式两种的,主动式不说是用户触发,被动式主要两种,一种是内存分配时候达到了控制计算的大小,还有一种是达到了预期时间(比如2分钟),这两种自动场景都会进行gc,它会做包括 STW->三色标记(mark)->回收(Sweep) 等主要步骤,这个过程是用户态程序不可控的。

    c. XMM的gc策略相对要高效很多,因为使用者需要调用Free()显示调用针对对象的标记(mark),XMM触发回收(Sweep) 动作只有一个,那就是内存容量达到了现有总容量的阈值(默认是75%) 才会进行Sweep,并且在Sweep的时候,因为XMM的所有空闲内存节点元素都是保存在span中的bitmap中的,扫描和释放速度非常快,很快就结束了。

    d. XMM跟go内置内存管理的没事就需要STW,扫描节点标记黑白灰然后Sweep的操作完全不同,虽然有混合写屏障等等,实际使用中还是会存在偶尔卡顿的情况。特别在元素非常多的情况下,比如说千万级元素,你想想每隔2分钟就会扫描一次,对于应用程序影响有多大,并且元素众多,需要进行黑白灰归类扫描,然后释放回收,绝对是性能会受到影响的。XMM不存在这个问题,标志是用户手动显示触发,但是回收过程都是内存达到容量使用的阈值,基本可以理解如果你申请内存足够大,有可能一直也遇不到GC的场景,如果遇到了,也只是简单访问一个bitmap(类数组)快速就结束了sweep工作。

    e. 从整个设计理念来看,Go的Gc本质是那种自助餐“勤拿少取,没事就收盘”的策略,会要求程序和Gc协程都是需要没事就进行扫描和回收工作的,但是XMM是自助餐“一把拿好,吃饱喝足”的策略,设计理念不同,决定了性能不同,当然使用场景也不同。在千万级别的item元素场景下,go的gc绝对是卡顿的,对于XMM来说是很轻松应付的。

  3. 关于单机alloc分配性能的问题:

    a. 因为大家在底层设计思路都是借鉴与tcmalloc的设计思想 heap+span 等等,大块内存申请策略也都是从内核通过mmap一块内存块出来,所以在alloc的性能在300多万每秒本质上是不会太大去吧的;

    b. 但是go内置内存管理在你alloc一个内存的时候,是很可能诱发gc的,那么这个时候会增加卡顿时间;而XMM除了达到了设定的内存使用阈值(目前是75%,可配置)才会gc,其它时间你都是可以轻松的alloc内存,如果申请元素非常少,大家性能是差不多的,那么在大部分场景下,或者元素稍微躲起来,肯定还是要XMM的alloc性能更高的。

  4. 结论: 所以综上所述,在需要超高性能,需要完成更多对象,需要自主内存可控制可管理场景,我觉得XMM是更好的选择!

回答内容有点多,希望对您有帮助,感谢~

参考链接: https://blog.csdn.net/stayfoolish_yj/article/details/104692374 https://www.jianshu.com/p/96a52a8127d9

bronze1man commented 2 years ago

谢谢。刚才又重新看了一遍,之前看的时候理解不对,总结一下:

新问题:对于xmm来说,我在同一个线程里面,刚alloc了16字节内存,用完之后,立刻free掉,然后我再alloc了16字节内存,是否会给我刚才的那个内存?如果这个答案是的话,可以通过这个机制在某些负载下有效利用cpu的缓存,以便大幅度提升cpu性能。

heiyeluren commented 2 years ago

问题:对于xmm来说,我在同一个线程里面,刚alloc了16字节内存,用完之后,立刻free掉,然后我再alloc了16字节内存,是否会给我刚才的那个内存?如果这个答案是的话,可以通过这个机制在某些负载下有效利用cpu的缓存,以便大幅度提升cpu性能。

回复: 一般不会马上复用刚才的16字节,会给你合适的空间找16字节,因为内部是采用 Class + Span + Slab 的逻辑来管理内存的,所以会找一个合适内存给你,实际也不一定是16字节,可能是32字节。:)