代码中的魔鬼细节
作者:互联网
软件开发最关心的三个指标:性能、内存、程序稳定性三方面。本文总结一下近期项目扫尾工作中的一些遭遇:
使用正确的哈希函数
道路的路况绘制,道路的颜色由三个ID唯一确定,他们存储在一个哈希表中。
上图是两种哈希函数的性能对照。
badHashFunction的结果为蓝色,goodHashFunction的结果为红色曲线。
使用坏的哈希函数,运行DJB_hash的结果冲突可能性十分大。因此哈希的平均查找次数很大,在性能很好的机器上拖动时也有明显的卡顿现象。
优化哈希函数,将三个ID的全部位数拼接成一个数字串。然后传入DJB_hash结果十分好,性能得到质的提升。
static unsigned int DJB_hash(int* buffer, int len)
{
unsigned int hash = 5381;
int i = 0;
while (i < len) {
hash += (hash << 5) + buffer[i++];
}
return (hash & 0x7FFFFFFF);
}
static unsigned int badHashFunction(const void* key)
{
rtic_t* ptr = (rtic_t*)key;
int buffer[3];
buffer[0] = ptr->mapId - RTIC_MIN_MAPID;
buffer[1] = ptr->kind;
buffer[2] = ptr->middle;
return DJB_hash(buffer, 3);
}
static unsigned int goodHashFunction(const void* key)
{
rtic_t* ptr = (rtic_t*)key;
const int SIZE = 20;
int buffer[SIZE] = {0};
int len = 0;
int v = ptr->mapId;
while (v && len < SIZE)
{
buffer[len++] = v % 10;
v /= 10;
}
v = ptr->kind;
while (v && len < SIZE)
{
buffer[len++] = v%10;
v /= 10;
}
v = ptr->middle;
while (v && len < SIZE)
{
buffer[len++] = v%10;
v /= 10;
}
return DJB_hash(buffer, len);
}
慎重使用vector
Vector的优点就是动态增长,使用起来很方便,仅仅管不断地push_back。不用关心内存添加的细节。Vector略微有经验的都知道,push_back之前应该先reserve。
这么做效率更高。
近期查我们项目的样式配置模块。突然发现内存占用十分厉害,前后情况例如以下:
样式载入前内存情况:
样式载入后内存情况:
单纯样式模块占用600K。
一路追查下去,结果哭笑不得。我们自己实现了一套C风格的Vector。里面存储void*指针从而实现泛型。Vector内部reserve函数实现很之坑爹,代码片段例如以下,每次reserve结果vector中至少有256个指针。
void TXVector::reserve(TXUINT32 capacity)
{
if (capacity <= _capacity)
{
return;
}
_capacity = capacity * 2;
if (_capacity < 256)
{
_capacity = 256;
}
上图为样式配置模块的数据结构,是个二维数组。当时由于赶项目进度,regionStyleList的每一个成员内部有一个vector。然而vector仅仅保存1-3个指针成员。RegionStyleList的数量很大,所以导致内存浪费十分严重。
优化时直接KISS(keep it simple and stupid)化,採用最简单的二维数组优化后,结果很明显,内存降到82K。
标签:魔鬼,hash,int,代码,len,buffer,细节,哈希,ptr 来源: https://www.cnblogs.com/ldxsuanfa/p/10812511.html