本系列文章采用实战+理论的分析方式,前两篇主要作为实战的入门教程。
在上一篇文章中我们展示了3种 malloc 算法的性能,并采用 Linux 的性能工具 ps 和 perf 分析了不同算法对缺页异常和 TLB 不命中的影响。为了让大家能快速尝试不同分配算法在你的应用上的性能情况,这篇文章将提供一个快速入门教程。
应用程序利用 malloc 和 free 等函数在堆空间中申请和释放动态内存。默认情况下,glibc 采用 PTMalloc 内存管理算法。为了采用不同的内存分配策略,我们只需要链接时采用指定库(比如TCMalloc)包含的 malloc/free 替换对应函数的默认实现即可。
TCMalloc 源码安装
wget https://github.com/gperftools/gperftools/releases/download/gperftools-2.7.90/gperftools-2.7.90.tar.gz
tar -xzf gperftools-2.7.90.tar.gz
cd gperftools-2.7.90
./configure --prefix=install_path(eg:$HOME/.local)
make && make install
JeMalloc 源码安装
git clone https://github.com/jemalloc/jemalloc.git
cd jemalloc
./autogen.sh
./configure --prefix=install_path
make
make install
链接替换
export LD_LIBRARY_PATH=install_path/lib/libjemalloc.so
or
export LD_LIBRARY_PATH=install_path/lib/libtcmalloc.so
只需安装和链接替换两个步骤,你就可以直接使用不同的内存分配策略了。是不是很简单?不过我们不能就此结束,那岂不是太没干货了!
问题1:为什么 LD_LIBRARY_PATH 能够完成相同函数的替换?
因为运行时动态库的搜索路径的先后顺序是:
1)编译目标代码时指定的动态库搜索路径;
2)环境变量LD_LIBRARY_PATH指定的动态库搜索路径;
3)配置文件/etc/ld.so.conf中指定的动态库搜索路径;
4)默认的动态库搜索路径/lib和/usr/lib;
由此可见,除了采用LD_LIBRARY_PATH的方式,用户还可以在编译时直接采用 -l 参数指定链接。
问题2:除了自己的应用程序开发外,TCMalloc/JeMalloc 还有哪些经典应用?
由于这两种内存管理算法对多线程场景非常有效。nginx mysql 等高并发的场景也都经常采用其作为性能优化的手段。
问题3:直接使用 JeMalloc 性能似乎有点不理想,有什么推荐参数配置吗?
我平时在使用 JeMalloc的时候通常采用如下配置:这里将dirty_decay_ms(默认10)设置成了一个非常大的值,主要是为了一直保留已申请的内存页不释放来减少缺页异常,缺点是导致物理内存占用率有点高,这个需要根据具体应用来平衡。可参考
jemalloc
https://www.freebsd.org/cgi/man.cgi?query=jemalloc&sektion=3
export MALLOC_CONF="oversize_threshold:1,background_thread:true,metadata_thp:auto,dirty_decay_ms:9000000000,muzzy_decay_ms:9000000000";
问题4:TCMalloc/JeMalloc 是如何向操作系统申请内存的?
通过系统调用brk和mmap系统调用向操作系统申请虚拟内存,这时候的虚拟内存并没有物理页面与之对应,只有当第一次访问该页面的时候操作系统才会选择相应的物理页面。关于具体的细节即将在系列文章(3)中进行详细的说明。
问题5:既是开源库,能够详细解释 TCMalloc 和 JeMalloc 的底层实现并解释它的应用场景吗?
可以的,后续系列文章 将会采用能要点突出,图文并茂的方式进行解读!此外,我们还会测试更多的深度学习模型在三种不同算法上性能表现情况,并着重分析为什么这种分配策略如何适用于这些深度学习负载。欢迎继续关注“程序员的大厂之路”微信公众号,更多精彩内容持续分享中…