减少memset的调
【说明】 内存操作函数memset/memset_s涉及到系统调用,其执行开销相对较大,尤其是在操作数据较大的场景下;因此对于大片内存,需合理设计其数据访问控制方式,应该减少memset的使用。
针对数据访问控制方式的建议如下:
- 数据标志位指示方法:可以通过设置标志变量,清除标志变量来实现相同的效果。具体地,可以在一个结构体的成员变量前增加一个标志变量,该变量如果被置为无效,则表示数据被清空;注意:需要确保对数据访问前判断标志位,避免访问无效数据。
- 字符串结束符标识方法:如果内存是用于存放字符串,可以利用填充字符串结尾‘\0’来优化。
【原理】
memset的性能分析(以Intel(R) Xeon(R) Gold 6161 CPU @ 2.20GHz为例):
memset |
1k |
1M |
10M |
1w次 |
180us |
288ms |
4300ms |
【注意事项】 针对上述数据标志位指示方法和字符串结束符标识方法,需要确保对数据进行访问之前,增加其有效性判断;另外,超过一定大小的结构体类型局部变量(需要注意的是,全局变量或静态变量的初始化不在此范围)使用“={0}”的方式进行初始化时,编译器也会隐式的调用memset,需要在编码阶段关注这种隐式调用。
【案例】
优化前:
struct MsgInfo {
uint8_t rawMsg[1000];
uint8_t msgKeyword;
};
void MsgInit(MsgInfo &info)
{
(void)memset_s(&info, sizeof(info), 0, sizeof(info));
}
说明:函数MsgInit参数info进行清零处理时,memset_s执行开销较大。
优化后:
struct MsgInfo {
bool msgIsValid;
uint8_t rawMsg[1000];
uint8_t msgKeyword;
};
void MsgInit(MsgInfo &info)
{
info.msgIsValid = false;
}
说明:通过msgIsValid有效标识对数据结构的有效性进行判断,函数MsgInit仅需要对该标志变量进行清零。
父主题: 语句