性能优化之个人见解

一、网络IO

1.对待高并发程序使用epoll模型替换select模型

2.根据网络数据量适当调整缓冲区大小

二、锁和原子操作

1.可以不使用锁就尽量少用锁,如果需要锁保证线程间数据同步就大胆使用锁

2.对象引用计数时可使用原子操作,gcc提供了__sync_*系列的函数,提供加减和逻辑运算的原子操作

返回值为更新前的值:

type __sync_fetch_and_add (type *ptr, type value, ...)

type __sync_fetch_and_sub (type *ptr, type value, ...)

type __sync_fetch_and_or (type *ptr, type value, ...)

type __sync_fetch_and_and (type *ptr, type value, ...)

type __sync_fetch_and_xor (type *ptr, type value, ...)

type __sync_fetch_and_nand (type *ptr, type value, ...)

返回值为更新后的值:

type __sync_add_and_fetch (type *ptr, type value, ...)

type __sync_sub_and_fetch (type *ptr, type value, ...)

type __sync_or_and_fetch (type *ptr, type value, ...)

type __sync_and_and_fetch (type *ptr, type value, ...)

type __sync_xor_and_fetch (type *ptr, type value, ...)

type __sync_nand_and_fetch (type *ptr, type value, ...)

比较 oldval 和 *ptr,如果它们相等,就把 newval 复制到 *ptr

如果 oldval 和*ptr 匹配,返回值是 true,否则是 false:

bool __sync_bool_compare_and_swap (type *ptr, type oldval type newval, ...)

返回操作之前的旧值:

type __sync_val_compare_and_swap (type *ptr, type oldval type newval, ...)

三、语言层面

1.构造函数中初始化类成员方式有两种,构造函数中初始化列表和赋值,如果类成员为类类型时,采用初始化列表方式性能有优势,如果类成员为int float内置类型却无差异。

class Base
{  
    int m_basemember;
public:  
    Base()
        : m_basemember(1) {
        printf("Base Construct Function\n");
    }  

    ~Base(){
        printf("Base Destruct Function\n");
    }

    Base(const Base& b) {
        printf("Base Copy constructor Function\n");
        this->m_basemember = b.m_basemember ;
    }

    Base& operator = (Base& b){  
        printf("Base operator = Function\n");
        this->m_basemember = b.m_basemember;  
        return *this;  
    }  
};  

class Derive  
{     
    Base m_base;  
public:  
    Derive (Base &base)
        /*:m_base(base)*/
    {  
        this->m_base = base;  
    }  
};

int main(int argc, char* argv[])
{
    Base base;
    Derive D(base);
    return 0;
}

在上例中:

如果Derive构造函数初始化方式为赋值方式,即this->m_base = base;,代码运行输出结果为:

Base Construct Function

Base Construct Function

Base operator = Function

Base Destruct Function

Base Destruct Function

如果Derive构造函数初始化方式为初始化列表,即:m_base(base),代码运行输出结果为:

Base Construct Function

Base Copy constructor Function

Base Destruct Function

Base Destruct Function

类类型使用初始化列表方式会少调用一次构造函数,在大量的类成员为类类型中初始化列表性能更好。

以下几种情况时必须使用初始化列表:

·常量成员,因为常量只能初始化不能赋值,所以必须放在初始化列表里面

·引用类型,引用必须在定义的时候初始化,并且不能重新赋值,所以也要写在初始化列表里面

·没有默认构造函数的类类型,因为使用初始化列表可以不必调用默认构造函数来初始化,而是直接调用拷贝构造函数初始化。

Note:

初始化类成员时,是按照声明的顺序初始化的,而不是按照出现在初始化列表中的顺序。

2.strlen和list容器中的size()函数

strlen的实现是遍历字符串直至’\0’,从而计算出字符串的len,如果是经常性计算或者字符串超长(HLS协议中当时移m3u8文件索引字符串长度会随着时移时间而增长),这种情况就不适合每次都strlen(str),可以自行用变量记录长度。

while(m_list.size() > 0) 这样的语句用while(!m_list.empty())替换,有些size()的实现是遍历链表才获得长度值,而不是用一个变量记录长度值。

3.临时对象

减少临时对象的产生。

四、内存使用

1.字节对齐

在不使用#pragma pack设定内存以多少字节对齐是,默认采用4字节对齐,方式1比方式2不管是在内存占用大小和访问变量时寻址方面都具有一定优势。

方式1

#pragma pack(4)
struct test
{
    int    a;
    short  b;
    char   c;
    double d;
};
#pragma pack(pop)

方式2
#pragma pack(4)
struct test
{
    char   c;
    double d;
    short  b;
    int    a;
};
#pragma pack(pop)

2.内存池

内存池的基本都是基于预分配大块内存,建立内存索引给外部使用,从而避免频繁创建释放内存导致效率低下。

3.内存拷贝

在流媒体服务器中音视频数据占用非常多的内存,程序模块间拷贝内存进行处理的现象也很多,个人经验尽量传递内存指针通过修改同一块内存避免大量的memcpy影响性能。

五、小结

从二八原则来看,影响程序性能的很有可能是20%的代码,而且没有必要过早的进入性能优化的阶段,也没有必要花大量时间在那80%代码身上。

可以在框架搭建阶段考虑性能瓶颈,在整体功能完成后通过性能工具来测试性能瓶颈并有针对性的优化。

以上都是泛泛的谈,但还是得具体问题具体分析具体解决。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值