代码优化指南(四)从内存模型说起

从C/C++内存开始说起

软件的核心是什么?

        从我过往的软件的经历来看,至少我了解过的,大部分应用软件的核心就是IO和内存,当然,IO也是基于内存的,所以也可以认为软件的核心就是怎么和内存交互(我们这里不讨论操作系统,文件调度,编译器这一类基础软件),所有的逻辑都是基于内存执行的,也就是说内存是优化的一个重要方向,怎么样使用内存,怎么样用更少的内存,怎么样更高效的利用内存,更快速的利用内存。

C++内存模型到底是怎么样的

        我们在网上搜索到的所有关于C/C++的所谓堆栈静态变量xxxx的内存模型,实际上和C++标准实际上没啥关系,C++的模型一直到C++11才和确定下来,但是这个内存模型本身也是抽象的模型,即C++的内存序号,C++内存序规定的是一个相对执行和重排顺序,给出下面一段代码

#include<atomic>
#include<thread>
std::atomic<int> a=1;
std::atomic<int> b=1;
int c=1;
int d=1;
void fun_1()
{
    while(1)
    {   
        c++;
        a.fetch_add(1,std::memory_order_release);
        b.load(std::memory_order_acquire);
    }
}


void fun_2()
{
    while(1)
    {
        d++;
        b.fetch_add(1,std::memory_order_release);
        a.load(std::memory_order_acquire);
    }
}

int main()
{
    std::thread t1(fun_1);
    std::thread t2(fun_2);
}


在内存序中,std::memory_order_release之前的指令一定不会被重排到这条指令之后,即当这条指令完成时,之前的指令一定完成,std::memory_order_acquire之后的指令一定不会被重排到这之前,但是至于之后的指令是否重排怎么重排则不在它的考虑范围内。

        那么我们一般看到的堆栈模型到底是来自于哪呢,较早的有提及到这个模型的书是《深入探索C++对象模型》,当然作者也明确表示C++标准中没有对这个模型进行定义,只是编译器和操作系统的惯常用法,即严格来说是Linux-gnu的内存模型,当然这个模型本身还是有很高的参考意义的。但是C++大量的优化操作实际上会打乱这个模型,如内联优化,将不再有call调用,不再有一个独立的所谓函数栈。同样的,在c++标准中未定义的数据本身实际上优化后的位置也是不定的

#include<assert>

int main()
{
    int i=1;
    int j=1;
    assert(&i==&j-1);        //报错

}


//gcc -O3

在gcc -O3优化下,十有八九这个断言将会报错。

C++内存模型继承自C,即在每两个数据中将会插入一个长度不定的不可访问区,这个访问区的长度可以很大也可以是0,也就是说不是符合所谓的堆栈区的。

c++标准库string的内存管理模式

        COW模式

        cow(写时复制)C++标准库对内存进行的一次优化尝试(当然现在的标准库大部分都不使用COW了)cow技术的关键在于当一个数据被复制时候,先不对内存进行复制,只是一个新指针还指向原来的位置(因为在函数传值得地方大量出现可能不会被修改的数据),只有当这个数据需要被修改时候才会有对内存进行复制,创建一个独立的副本进行修改,这样将会很好的减少内存的复制次数。当然这个技术被废弃的原因在于在多线程中,很难判断这个数据到底是本线程独有还是和其他线程共有,也就是写时复制将会失效。

        SSO模式

        目前使用最多的技术,我们知道在通常情况下string的内存是在栈(用Linux的内存模型)上有一个胖指针,然后再堆上有一组连续空间用于存储数据,但是我们知道在堆上分配内存需要和操作系统交互,在之前的文章中我们已经申明了和操作系统交互的代价是特别大的,因此string的实现会使用两个技巧可以供我们借鉴

        a.空间的超量分配

        在使用string的时候我们经常会对字符串进行增减,因此在分配空间的时候标准库一般都会向操作系统申请超量的空间,当在一定范围内长度增长,不需要申请新的空间。

        b.sso技术

        大部分的字符串的长度都是很小的,因此在很多时候C++直接在栈上构建字符串(即字符串的本体也存储在栈上获取更好的性能,当字符串增长到一定程度的时候再整体复制到堆上,把栈上的空间释放。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值