Open bronze1man opened 2 years ago
感谢 @bronze1man 提问,问题提的都非常好,一一给您解答。
内存管理均衡性问题:
从设计机制上面来说,XMM和go内置的gc机制没有太本质区别,都是从用户态通过系统调用mmap的方式从内核申请一大块内存进行管理,go内置内存管理和XMM在这个设计上是基本一样的,go的内存管理和XMM底层都是从tcmalloc中学习的设计思想,所以在常态使用中(不会gc,元素很少)中使用go内置内存管理和XMM都是没有太大区别,只是XMM个人可控性更强一些。
关于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来说是很轻松应付的。
关于单机alloc分配性能的问题:
a. 因为大家在底层设计思路都是借鉴与tcmalloc的设计思想 heap+span 等等,大块内存申请策略也都是从内核通过mmap一块内存块出来,所以在alloc的性能在300多万每秒本质上是不会太大去吧的;
b. 但是go内置内存管理在你alloc一个内存的时候,是很可能诱发gc的,那么这个时候会增加卡顿时间;而XMM除了达到了设定的内存使用阈值(目前是75%,可配置)才会gc,其它时间你都是可以轻松的alloc内存,如果申请元素非常少,大家性能是差不多的,那么在大部分场景下,或者元素稍微躲起来,肯定还是要XMM的alloc性能更高的。
结论: 所以综上所述,在需要超高性能,需要完成更多对象,需要自主内存可控制可管理场景,我觉得XMM是更好的选择!
回答内容有点多,希望对您有帮助,感谢~
参考链接: https://blog.csdn.net/stayfoolish_yj/article/details/104692374 https://www.jianshu.com/p/96a52a8127d9
谢谢。刚才又重新看了一遍,之前看的时候理解不对,总结一下:
新问题:对于xmm来说,我在同一个线程里面,刚alloc了16字节内存,用完之后,立刻free掉,然后我再alloc了16字节内存,是否会给我刚才的那个内存?如果这个答案是的话,可以通过这个机制在某些负载下有效利用cpu的缓存,以便大幅度提升cpu性能。
问题:对于xmm来说,我在同一个线程里面,刚alloc了16字节内存,用完之后,立刻free掉,然后我再alloc了16字节内存,是否会给我刚才的那个内存?如果这个答案是的话,可以通过这个机制在某些负载下有效利用cpu的缓存,以便大幅度提升cpu性能。
回复: 一般不会马上复用刚才的16字节,会给你合适的空间找16字节,因为内部是采用 Class + Span + Slab 的逻辑来管理内存的,所以会找一个合适内存给你,实际也不一定是16字节,可能是32字节。:)
请给我一个我会引入这个库的一个具体理由。
是否有对比实验证明这个库在某种tradeoff的情况下比golang自带的好?好多少?我自己是否可以在我的机器上运行这类对比实验?
看描述似乎这个库本身也带一个gc功能。那么在与官方golang的gc做的事情一样的情况下如何还能比官方golang的gc还好,就值得怀疑。
另外 单机(6 核心 KVM 或物理机)内存分配性能达到 350w+ alloc/s;(每秒内存分配速度); 好像官方的golang的分配速度也是这个水平上(没有具体的机器谈具体的性能算扯淡哈),那边必然是在其他方面有优化,比如没有 gc 对吞吐量的延时影响?具体优化了啥?文档上没讲。