body, table{font-family: 微软雅黑; font-size: 10pt}
table{border-collapse: collapse; border: solid gray; border-width: 2px 0 2px 0;}
th{border: 1px solid gray; padding: 4px; background-color: #DDD;}
td{border: 1px solid gray; padding: 4px;}
tr:nth-child(2n){background-color: #f8f8f8;}

1、Scott Meyers
、推荐我们,在真正需要一个存储空间时才去声明变量(分配内存),这样会得到程序在运行时最小的内存花销
2、执行到那才会去做分配内存这种比较耗时的工作,这会给我们的程序在运行时有比较好的性能写时才拷贝(Copy-On- Write)技术,是编程界“懒惰行为”——拖延战术的产物
#include <iostream>
#include<string>
#include<stdio.h>
using namespace std;
int main()
{
        string str1="hello world";
        string str2=str1;
        string str3=str2;
        printf("str1 = %p\n",str1.c_str());
        printf("str2 = %p\n",str2.c_str());
        printf("str3 = %p\n",str3.c_str());
        str1[1]='X';
        cout<<"after Copy-on-Write"<<endl;
        printf("str1 = %p\n",str1.c_str());
        printf("str2 = %p\n",str2.c_str());
        printf("str3 = %p\n",str3.c_str());
        return 0;
}
● string类中有一个私有成员,其实是一个char*,记录从堆上分配内存的地址,其在构造时分配内存,在析构时释放内存
● 因为是从堆上分配内存,所以string类在维护这块内存上是格外小心的
● string类在返回这块内存地址时,只返回const char*,也就是只读的
● const char* c_str() const;
● 如果要写,则只能通过string提供的方法进行数据的改写。

Copy-On-Write的原理是什么?

● Copy-On-Write一定使用了“引用计数”,必然有一个变量类似于RefCnt
● 当第一个string对象str1构造时,string的构造函数会根据传入的参数从堆上分配内存
● 当有其它string对象复制str1时,这个RefCnt会自动加1
● 当有对象析构时,这个计数会减1;直到最后一个对象析构时,RefCnt为0,此时,程序才会真正的Free这块从堆上分配的内存
string类在什么情况下才共享内存的?

1)以一个对象构造自己(复制构造函数)
只需要在string类的拷贝构造函数中做点处理,让其引用计数累加
2)以一个对象赋值(重载赋值运算符)
string类在什么情况下触发写时才拷贝?

● 在共享同一块内存的类发生内容改变时,才会发生Copy-On-Write
● 比如string类的 []、=、+=、+、操作符赋值,还有一些string类中诸如insert、replace、append等成员函数
Copy-On-Write时,发生了什么?

if  ( --RefCnt>0 ) {       
    char* tmp =  (char*) malloc(strlen(_Ptr)+1);       
    strcpy(tmp, _Ptr);       
    _Ptr = tmp;
}
引用计数RefCnt 大于1,表示这个内存是被共享的。
Copy-On-Write的具体实现是怎么样的?

string h1 = "hello";
string h2= h1;
string h3;
h3 = h2;
string w1 = "world";
string w2("");
w2=w1;

h1、h2、h3共享同一块内存, w1、w2共享同一块内存

Copy-On-Write的具体实现是怎么样的?

● String类创建的对象的内存是在堆上动态分配的,既然共享内存的各个对象指向的是同一个内存区,那我们就在这块共享内存上多分配一点空间来存放这个引用计数RefCnt
● 这样一来,所有共享一块内存区的对象都有同样的一个引用计数
解决方案:
当为string对象分配内存时,我们要多分配一个空间用来存放这个引用计数的值,只要发生拷贝构造或赋值时,这个内存的值就会加1。而在内容修改时,string类为查看这个引用计数是否大于1,如果refcnt大于1,表示有人在共享这块内存,那么自己需要先做一份拷贝,然后把引用计数减去1,再把数据拷贝过来

COW写时复制的更多相关文章

  1. 用户空间缺页异常pte_handle_fault()分析--(下)--写时复制【转】

    转自:http://blog.csdn.net/vanbreaker/article/details/7955713 版权声明:本文为博主原创文章,未经博主允许不得转载. 在pte_handle_fa ...

  2. Rust写时复制Cow<T>

    写时复制(Copy on Write)技术是一种程序中的优化策略,多应用于读多写少的场景.主要思想是创建对象的时候不立即进行复制,而是先引用(借用)原有对象进行大量的读操作,只有进行到少量的写操作的时 ...

  3. JAVA中写时复制(Copy-On-Write)Map实现

    1,什么是写时复制(Copy-On-Write)容器? 写时复制是指:在并发访问的情景下,当需要修改JAVA中Containers的元素时,不直接修改该容器,而是先复制一份副本,在副本上进行修改.修改 ...

  4. fork()和写时复制

    写时复制技术最初产生于Unix系统,用于实现一种傻瓜式的进程创建:当发出fork(  )系统调用时,内核原样复制父进程的整个地址空间并把复制的那一份分配给子进程.这种行为是非常耗时的,因为它需要: · ...

  5. Linux的fork()写时复制原则(转)

    写时复制技术最初产生于Unix系统,用于实现一种傻瓜式的进程创建:当发出fork(  )系统调用时,内核原样复制父进程的整个地址空间并把复制的那一份分配给子进程.这种行为是非常耗时的,因为它需要: · ...

  6. Linux进程管理——fork()和写时复制

    写时复制技术最初产生于Unix系统,用于实现一种傻瓜式的进程创建:当发出fork(  )系统调用时,内核原样复制父进程的整个地址空间并把复制的那一份分配给子进程.这种行为是非常耗时的,因为它需要: · ...

  7. 写时复制和fork,vfork,clone

    写时复制 原理: 用了“引用计数”,会有一个变量用于保存引用的数量.当第一个类构造时,string的构造函数会根据传入的参数从堆上分配内存,当有其它类需要这块内存时,这个计数为自动累加,当有类析构时, ...

  8. Redis持久化之父子进程与写时复制

    之所以将Linux底层的写时复制技术放在Redis篇幅下,是因为Redis进行RDB持久化时,BGSAVE(后面称之为"后台保存")会开辟一个子进程,将数据从内存写进磁盘,这儿我产 ...

  9. phpCOW机制(写时复制)

    写时复制(Copy-on-Write,也缩写为COW),顾名思义,就是在写入时才真正复制一份内存进行修改. COW最早应用在*nix系统中对线程与内存使用的优化,后面广泛的被使用在各种编程语言中,如C ...

随机推荐

  1. 论文笔记:Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift

    ICML, 2015 S. Ioffe and C. Szegedy 解决什么问题(What) 分布不一致导致训练慢:每一层的分布会受到前层的影响,当前层分布发生变化时,后层网络需要去适应这个分布,训 ...

  2. centos7下配置iptables实现外网访问内网服务器

    说明:Centos 7 默认的防火墙是 firewall,安装iptables之前需关闭Firewall 外网机器:外网ip:120.25.71.183内网ip:10.1.1.23 内网机器:内网ip ...

  3. [原创] css中的绝对定位和相对定位

    我对博客的认识是:记录问题,解决问题,分享知识.如果有轮子,我不需要造轮子.   首先,定位无论是相对定位还是绝对定位,必须有一个参考项,而这个参考项,专业术语称之为 包含块,这里的包含块是指在定位时 ...

  4. Python基本数据类型之列表

    学习Python的列表类型需要了解和掌握什么是列表.列表的可变性.列表的访问.列表的增删改查等操作~ 1.了解列表 list1 = ['abc', 123, {1, 2, 3},[2,3]] Pyth ...

  5. LCD1602

    一.关于LCD1602: 在编写LCD1602程序前,我们必须了解其手册上一些非常重要的信息,如果这些信息不能理解透彻,编程可能会遇到或多或少的问题,在此先大致归纳几点. 1.管脚: 1602共16个 ...

  6. SVN添加忽略目录

    项目:Thinkphp 目录结构: Thinkphp |-- Common |-- Runtime |-- Home 忽略目标: Runtime 文件夹及下面所有文件 首先,需要忽略的目录必须没有加入 ...

  7. Centos下ftp协议连接远程ftp server主机

    环境说明 [root@Check3 ~]# cat /etc/redhat-release CentOS release 6.9 (Final) [root@Check3 ~]# uname -a L ...

  8. 机器学习:让我们彻底搞懂CNN【转】

    本文转载自:http://115.com/182920/T1266078.html 机器学习:让我们彻底搞懂CNN 上世纪科学家们发现了几个视觉神经特点,视神经具有局部感受眼,一整张图的识别由多个局部 ...

  9. SpringBoot 集成Netty实现UDP Server

    注:ApplicationRunner 接口是在容器启动成功后的最后一步回调(类似开机自启动). UDPServer package com.vmware.vCenterEvent.netty; im ...

  10. vue集成ueditor

    相关代码见github 1.引入ueditor相关的文件,具体目录见下图如下 我将下载的文件放在static下面,这里专门用来放置相关的静态文件 (在ueditor.config.js需要配置一下路径 ...