b.消除指针链
访问多级结构体成员变量时常要使用指针链,如:
typedef struct { int x, y, z; }point;
typedef struct {point *pos, *direct; }obj;
void InitPos(obj *p)
{
p->pos->x = 0;
p->pos->y = 0;
p->pos->z = 0;
}
如果编译器不能确定p->pos->x不是p->pos的别名,代码中每次赋值操作都要重新访问p->pos(了解下restrict)。所以最好是手动把p->pos存到一个局部变量,改为:
void InitPos(obj *p)
{
point *pos = p->pos;
pos->x = 0;
pos->y = 0;
pos->z = 0;
}
这样只需一次p->pos内存访问,比之前省了两次。而且这不是节省两条普通指令,而是两条访问随机内存的指针链操作。
二、集中连续访问内存包括:
a. 合理安排和调整循环次序
循环中的内存访问多数都是性能热点,是连续集中还是断续分散访问,很大程度影响系统性能。有时仅仅调整循环次序,使分散内存访问变得连续,就能大幅提升性能。如:
for(i=0;i for(j=0;j A(j,i) = B(j,i) + C(j,i) * D
变为:
for(j=0;j for(i=0;i A(j,i) = B(j,i) + C(j,i) * D
交换后, A, B, C均按其在内存中的排列顺序依次被访问,而不是像之前那样跳跃式访问。访问内存就象逛街购物,好不容易出来一次,自然要尽量把需要的东西都买回去,否则又要多跑,这中间是需要时间代价。
b.使用连续内存的数据结构
链表结构相比数组,对内存的占用更少且更灵活,但在内存访问密集型的应用中却会导致性能的明显下降,因为访问链表节点是分散随机地访问内存。与之对应访问数组内存则相对集中且连续,所以如果对链表的随机访问成为性能阻碍,不妨考虑用数组代替链表,或者从预分配的大块连续内存上分配链表节点,而不是用malloc随机申请内存块。注意: 无论cache或non-cache系统中,把离散内存访问变为连续内存访问都能提高系统性能。而如何写出cache-friendly的代码则是更高级的主题。
以上只是从内存角度出发,C语言级优化的几个基本着眼点,仅为大家抛砖引玉。