Nginx在内存使用方面做了较多优化,其中有一项就是内存对齐。内存对齐都有哪些好处?单从Nginx的代码来看,有两点:
1. 减少CPU访问内存次数,我们知道CPU都有一个叫做总线宽度的东西,我们平时所说的32位CPU,其实就是它的总线宽度是32位,也就是一次能读32/8=4个字节。假设有一块内存地址为0 1 2 3 4 5 6 7八个字节,CPU从该内存中读一个整数出来,如果该整数占据着 0 1 2 3四个字节,则CPU可以一次读出;如果该整数占据着 2 3 4 5,则CPU需要读两次内存,这样看来变量在内存中的布局会影响到CPU访问内存的次数,如果该变量访问很频繁的话,比如应用系统中访问量很大的缓存数据,该程序就有优化的空间。
2. 尽量与CPU缓存字或者系统内存页块对齐,能占用一个缓存条目的不占据两条,这样能提高高速缓存的利用率,我们可以看到Nginx中运行时频繁使用的crc32表数据就考虑了CPU高速缓存字对齐。src/core/ngx_cpuinfo.c有获取各种类型CPU高速缓存条目的代码。src/os/unix/ngx_posix_ini.c的函数ngx_os_init中有获取操作系统缓存页大小的代码。
下面来看一下Nginx获取对齐内存地址的方法:
#define ngx_align(d, a) (((d) + (a - 1)) & ~(a - 1))
这个宏本质上是计算大于d的a的最小倍数。一般来说a是2的幂运算。比如说a=8,也就是一个字节对齐,a-1二进制形式就是0111。根据d的值,会有两种情况出现:
1)当d是a的整数倍时,其最低三位都是0,加上a-1,最低三位就变成全1,然后与~(a - 1)按位与后最低又三位变成全0,高于3位的部分未变,所以当d是a的整数倍时,ngx_align(d, a)等于d。
2)当d不是a的整数倍时,由于d的低三位有1出现,加上0111后第四位会进一,当和~(a - 1)与运算后低三位变为全0,这样就是a的整数倍了,高于低三位的部分获得了一个进位,所以刚好是大于d的a的最小倍数。