COW copy on write linux 开博啦。哈哈

 

今天看Linux的内容时找到的。 但运行时发现copy时地址已经不值向同一块内存了。为什么呢??

STL标准模板库中的string类,也是一个具有写时才拷贝技术的类。C++曾在性能问题上被广泛地质疑和指责过,为了提高性能,STL中的许多类都采用了Copy-On-Write技术。通常,string类中必有一个私有成员,其是一个char*,用户记录从堆上分配内存的地址,其在构造时分配内存,在析构时释放内存。因为是从堆上分配内存,所以string类在维护这块内存上是格外小心的,string类在返回这块内存地址时,只返回const char*,也就是只读的,如果你要写,你只能通过string提供的方法进行数据的改写。

main()

{

string str1 = "hello world";// string str1 ("hello world"); 调用的是构造函数

    string str2 = str1; // string str2 (str1); 调用的是拷贝构造函数

//此时str1,str2共享内存

    printf ("Sharing the memory:/n");

    printf ("/tstr1's address: %x/n", str1.c_str() );

    printf ("/tstr2's address: %x/n", str2.c_str() );

    str1[1]='q';

    str2[1]='w';

/*当然是在共享同一块内存的类发生内容改变时,才会发生Copy-On-Write。比如string类的[]=+=+、操作符赋值,还有一些string类中诸如insertreplaceappend等成员函数。*/

    printf ("After Copy-On-Write:/n");

    printf ("/tstr1's address: %x/n", str1.c_str() );

    printf ("/tstr2's address: %x/n", str2.c_str() );

    return 0;

}

结果:

Sharing the memory:

        str1's address: 12ff3c //非343be9???

        str2's address: 12ff14 //非343be9

After Copy-On-Write:

        str1's address: 3407a9

        str2's address: 343be9

str1str2存放数据的地址是一样的,而在修改内容后,str1的地址发生了变化,而str2的地址还是原来的。从这个例子,我们可以看到string类的Copy-On-Write技术。

引用计数就是string类中写时才拷贝的原理,RefCnt表示使用共享内存个对象个数。当共享内存被修改的时候,采用下面的假想代码操作:

If  ( RefCnt>0 ) {

    char* tmp =  (char*) malloc(strlen(_Ptr)+1);

    strcpy(tmp, _Ptr);

    _Ptr = tmp;

}

每当我们为string分配内存时,我们总是要多分配一个空间用来存放这个引用计数的值,只要发生拷贝构造可是赋值时,这个内存的值就会加一。而在内容修改时,string类为查看这个引用计数是否为0,如果不为零,表示有人在共享这块内存,那么自己需要先做一份拷贝,然后把引用计数减去一,再把数据拷贝过来。下面的几个程序片段说明了这两个动作:

//构造函数(分存内存)

string::string(const char* tmp)

{

    _Len = strlen(tmp);

    _Ptr = new char[_Len+1+1];

    strcpy( _Ptr, tmp );

    _Ptr[_Len+1]=0;  // 设置引用计数  

}

//拷贝构造(共享内存)

    string::string(const string& str)

    {

         if (*this != str){

              this->_Ptr = str.c_str();   //共享内存

              this->_Len = str.szie();

              this->_Ptr[_Len+1] ++;  //引用计数加一

         }

}

//写时才拷贝Copy-On-Write

char& string::operator[](unsigned int idx)

{

    if (idx > _Len || _Ptr == 0 ) {

         static char nullchar = 0;

         return nullchar;

          }

    _Ptr[_Len+1]--;   //引用计数减一

    char* tmp = new char[_Len+1+1];

    strncpy( tmp, _Ptr, _Len+1);

    _Ptr = tmp;

    _Ptr[_Len+1]=0; // 设置新的共享内存的引用计数   

    return _Ptr[idx];

}

在标准库里面,把这个引用计数的内存分配在了前面,分配在前的好处是当string的长度扩展时,只需要在后面扩展其内存,而不需要移动引用计数的内存存放位置,这又节省了一点时间。_Ptr指着是数据区,而RefCnt则在_Ptr-1 或是 _Ptr[-1]处。

 

注意:cstr();函数可以让共享内存的两个完全相同的string对象分为存储在两个不同的内存区域的对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值