Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
bronze1man opened this issue Feb 24, 2022 · 3 comments

Comments

@bronze1man
Copy link

bronze1man commented Feb 24, 2022

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

  • 是否有对比实验证明这个库在某种tradeoff的情况下比golang自带的好?好多少?我自己是否可以在我的机器上运行这类对比实验?

  • 看描述似乎这个库本身也带一个gc功能。那么在与官方golang的gc做的事情一样的情况下如何还能比官方golang的gc还好,就值得怀疑。

  • 另外 单机(6 核心 KVM 或物理机)内存分配性能达到 350w+ alloc/s;(每秒内存分配速度); 好像官方的golang的分配速度也是这个水平上(没有具体的机器谈具体的性能算扯淡哈),那边必然是在其他方面有优化,比如没有 gc 对吞吐量的延时影响?具体优化了啥?文档上没讲。

@heiyeluren
Copy link
Owner

感谢 @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
Copy link
Author

bronze1man commented Mar 1, 2022

谢谢。刚才又重新看了一遍,之前看的时候理解不对,总结一下:
* 理论上讲 xmm的gc的cpu代价极小。因为最费时间,最麻烦的 mark操作由调用者执行。理论上讲,其实也没办法进行类似golang的mark操作,因为无法获取内存引用数信息。
* tradeoff 代价是调用者需要正确找到所有 free 的地方。如果调用者忘记调用free,那么就会爆内存。

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

@heiyeluren
Copy link
Owner

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

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants