写时拷贝技术(Copy-On-Write)

写时拷贝技术(copy-on-write)

抛砖引玉:

  • 《More Effective C++》中讲过一个例子:在你还在上学的时候,你的父母要你不要看电视,而去复习功课,于是你把自己关在房间里,做出一副正在复习功课的样子,其实你在干着别的诸如给班上的某位女生写情书之类的事,而一旦你的父母出来在你房间要检查你是否在复习时,你才真正捡起课本看书。这就是“拖延战术”,直到你非要做的时候才去做。

这种现实生活中的小套路,转变到编程世界里就成为了最有用的技术。正如C++中的可以随处声明变量的特点一样,Scott Meyers推荐我们,在真正需要一个存储空间时才去声明变量(分配内存),这样会得到程序在运行时最小的内存花销。执行到那才会去做分配内存这种比较耗时的工作,这会给我们的程序在运行时有比较好的性能。毕竟20%的程序运行了80%的时间(二八定律)。

拖延战术:

  • 在真正需要一个存储空间时才去声明变量(分配内存),这样会得到程序在运行时最小的内存花销。

  • 当一个程序运行结束时,操作系统并不会急着把其清除出内存,原因是有可能程序还会马上再运行一次(从磁盘把程序装入到内存是个很慢的过程),而只有当内存不够用了,才会把这些还驻留内存的程序清出。

  • 写时才拷贝(Copy-On-Write)技术

二八定律

二八定律是19世纪末20世纪初意大利经济学家巴莱多发现的。他认为,在任何一组东西中,最重要的只占其中一小部分,约20%,其余80%尽管是多数,却是次要的,因此又称二八定律。

写时拷贝技术概念

程序需要根据网络持续传递的数据进行写操作,如果每一次写操作都通过fwrite或fprintf函数来进行一个磁盘的I/O读取的话,性能损失巨大。因此,一般的做法是每次写文件操作都写在一块特定大小的内存中(磁盘缓存),只有当接收完一段数据需要关闭文件时,才写到磁盘上。虽然上述方法能够提高性能,但同样会带来诸如非正常退出,数据丢失或文件损坏的风险。

标准C++类std::string的Copy-On-Write

STL标准模板库中的string类,就是一个具有写时才拷贝技术的类。C++曾在性能问题上被广泛地质疑和指责过,为了提高性能,STL中的许多类都采用了Copy-On-Write技术。这种偷懒的行为的确使使用STL的程序有着比较高要性能。

string类内存分配的概念

通常string类中必有一个私有成员,其是一个char*,用户记录从堆上分配内存的地址,其在构造时分配内存,在析构时释放内存。
因为是从堆上分配内存,所以string类在维护这块内存上是格外小心的,string类在返回这块内存地址时,只返回const char*,也就是只读的,如果需要写,只能通过string提供的方法进行数据的改写。

测试程序

#include<iostream>
#include<stdio.h>
#include<string>

using namespace std;
main()
{
    string str1 = "hello world";
    string str2 = str1;
    
    cout<<"Sharing the memory:"<<endl;
    cout<<"str1's address: "<<(void *)(str1.c_str())<<endl;
    cout<<"str2's address: "<<(void *)(str2.c_str())<<endl;
    
    str1[1]='q';
    str2[1]='w';
 
    cout<<"After Copy-On-Write:"<<endl;
    cout<<"str1's address: "<<(void *)(str1.c_str())<<endl;
    cout<<"str2's address: "<<(void *)(str2.c_str())<<endl;
 
    return 0;
}

执行结果:

[root@iZuf61kbf845xt6tz10abgZ code]# g++ -o stringTest stringTest.cpp

理论上:
[root@iZuf61kbf845xt6tz10abgZ code]# ./stringTest
Sharing the memory:
str1's address: 0x7fff54c24b70
str2's address: 0x7fff54c24b70
After Copy-On-Write:
str1's address: 0x7fff54c24b70
str2's address: 0x7fff54c24b50
    

实际上:
[root@iZuf61kbf845xt6tz10abgZ code]# ./stringTest
Sharing the memory:
str1's address: 0x7fff54c24b70
str2's address: 0x7fff54c24b50
After Copy-On-Write:
str1's address: 0x7fff54c24b70
str2's address: 0x7fff54c24b50
    

即不同的gcc或vs编译器对共享内存有不同的处理策略。有的环境可能直接是深拷贝,有的环境是共享内存。(扩展不同编译器的优化策略也不尽相同)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
写时复制(Copy-on-Write,简称COW)策略是一种用于优化内存和时间效率的技术,常用于操作系统、数据库以及编程语言的实现中。 在COW策略中,当多个进程或线程共享同一份资源或数据时,不会立即复制这份资源或数据,而是共享同一份拷贝,只有在某个进程或线程需要修改这份数据时才会执行实际的复制操作。 具体来说,在资源或数据被多个进程或线程共享时,它们实际上共享同一份只读的拷贝。当某个进程或线程需要修改这份数据时,会先执行一次复制操作,然后修改复制后的数据,而其他进程或线程仍然共享原始的只读拷贝。这样一来,当需要修改的进程或线程比较少时,就可以避免大规模的复制操作,从而提高内存和时间效率。 COW策略的优点在于减少了复制操作的开销,节省了内存的使用。当多个进程或线程共享大规模数据时,COW可以避免大规模的数据复制,减少内存的占用,从而减少了系统开销。同时,COW也提高了并发性,因为不需要加锁来保护原始拷贝的数据,只有在修改时才需要加锁。 然而,COW策略也存在一些缺点。首先,每次数据修改都需要复制一份数据,而且当修改操作频繁时,复制操作的开销可能逐渐积累起来,降低了效率。此外,COW策略的实现也较为复杂,需要额外的开销和处理逻辑。 总之,COW策略是一种用于优化内存和时间效率的技术,通过延迟实际的数据复制操作,同时共享同一份只读数据拷贝,从而提高系统的性能和并发性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值