文章目录
- 概述
- JEMALLOC
- 内存碎片
- Redis 中的 Jemalloc
- libatomic 缺失,引起的编译失败
- [jemalloc] unsupported system page size
- 扩展
- 小结
概述
简明扼要,本文主要分析及解决以下两个问题
- 因操作系统缺少基础的动态库,比如libatomic 引起的编译和运行失败
- 因操作系统PAGE SIZE差异,导致的启动报错 [jemalloc] unsupported system page size
JEMALLOC
我们先看JEMALLOC
JEMALLOC是什么呢?
github: https://github.com/jemalloc/jemalloc
jemalloc is a general purpose malloc(3) implementation that emphasizes fragmentation avoidance and scalable concurrency support
通俗来说,也是内存管理算法, 但是在避免内存碎片与并发扩展要好
内存分配器ptmalloc,jemalloc,tcmalloc调研与对比
内存碎片
既然在jemalloc避免内存碎片与并发扩展要好, 那什么是内存碎片呢?
假设一个简单的玩具示例,你有10个字节的内存:
| | | | | | | | | | |
0 1 2 3 4 5 6 7 8 9
现在让我们分配三个三字节块,名称A,B和C:
| A | A | A | B | B | B | C | C | C | |
0 1 2 3 4 5 6 7 8 9
现在解除分配块B:
| A | A | A | | | | C | C | C | |
0 1 2 3 4 5 6 7 8 9
现在如果我们尝试分配一个四字节的块D会发生什么?
虽然内存空间里有四个字节的内存空闲,但没有四个连续的内存字节,所以不能分配D!同时,也不能移动C来腾出空间,因为程序中的某些变量很可能指向C,所以我们无法自动查找和更改所有这些值。
Redis 中的 Jemalloc
Redis在2.4及2.4以后的版本中,内存管理默认使用Facebook开源的jemalloc
我们从源码中的Makefile文件可以看到
ifeq ($(uname_S),Linux)
ifneq ($(FORCE_LIBC_MALLOC),yes)
USE_JEMALLOC=yes
endif
endif
如果是Linux操作系统,且没有强制使用GLIBC , 则使用JEMALLOC
你如果找2.4.0之前版本的MakeFile ,是没有这个逻辑的。
libatomic 缺失,引起的编译失败
运行时动态库的搜索路径的先后顺序是:
- 1)编译目标代码时指定的动态库搜索路径;
- 2)环境变量LD_LIBRARY_PATH指定的动态库搜索路径;
- 3)配置文件/etc/ld.so.conf中指定的动态库搜索路径;
- 4)默认的动态库搜索路径/lib和/usr/lib;
5.0.8 及 5.0.8以后的版本中,redis源码中的Makefile ,增加了这么一段逻辑
ARM架构(V8 ,V6)下 ,使用libatomic。
那怎么解决呢?
如果必须使用,则需要将对应的 rpm包安装以后, /usr/lib64建立软连接
然后,make distclean 后再 make
5.0.7 及 5.0.7 一下版本,未使用到
[jemalloc] unsupported system page size
3个常见的页大小
- 4096 4k
- 16384 16K
- 65536 64k
4K环境上编译的,无法在16和64上运行,
反之可以。
为避免出问题,建议统一在64K的 机器上编译
getconf PAGESIZE
可查看页大小
扩展
Google TCMalloc:Thread-Caching Malloc
https://github.com/google/tcmalloc
小结
- 作为基础库的ptmalloc是最为稳定的内存管理器,无论在什么环境下都能适应,但是分配效率相对较低。
- tcmalloc针对多核情况有所优化,性能有所提高,但是内存占用稍高,大内存分配容易出现CPU飙升。
- jemalloc的内存占用更高,但是在多核多线程下的表现也最为优异。