在看 Nginx 内存池实现的时候,在 ngx_slab_init
函数的实现中最后有一个内存对齐的操作:
pool->start = (u_char *)
ngx_align_ptr((uintptr_t) p + pages * sizeof(ngx_slab_page_t),
ngx_pagesize);
其中p
是指针,ngx_pagesize
是页的大小,该操作就是向前移动p
使其是ngx_pagesize
的整数倍,ngx_align_ptr
实现如下:
#define ngx_align_ptr(p, a) \\
(u_char *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1))
这段代码着实迷惑了我一下,想了半天,才发现自己在知识的运用上还是太生疏了:
- 内存页都是 2 的幂,如 x86 的页是就是 4096( 即
2 ^ 12
,即0b1000000000000
) - 指针是无符号数
- 于是问题就变成了将一个无符号整数“上调”到最近的 2 的幂(4096)的倍数
分析到这里,一下了就想到了一本神书“Hacker’s Delight”(中文译作《高效算法的奥秘》),拿来一看第三章说的恰恰是这个问题!这本书在读研究生时在图书馆看过,但是只当时觉得神奇,看完了除了能“装”一下也不知道有什么用处,而“装”这个事在软件工程中总是不被提倡的,所以看了前几章也就放下了,今天终于“啊哈!”了一下。
对于上面宏中的p
和a
(总是 0b10000 这样的形式),先看看下调:p & -a
,其实就是把p
后面和a
中后面 0 同样多的的位置 0,也就是p & ~(a-1)
。
有了下调,上调就简单了,只要对p+(a-1)
下调即可,即(p+(a-1)) & ~(a-1)
,这就是ngx_align_ptr
的内容了。
总结:
- 知识总不嫌多,看不到实际应用是因为学识还不够
- 可以不记住所有细节,但是用时一定会记起出处
- 写点注释能死啊!