C++寫(xiě)時(shí)拷貝實(shí)現(xiàn)原理及實(shí)例解析
一、什么是寫(xiě)時(shí)拷貝
寫(xiě)入時(shí)復(fù)制是一種計(jì)算機(jī)程序設(shè)計(jì)領(lǐng)域的優(yōu)化策略。其核心思想是,如果有多個(gè)調(diào)用者同時(shí)請(qǐng)求相同資源(如內(nèi)存或磁盤(pán)上的數(shù)據(jù)存儲(chǔ)),他們會(huì)共同獲取相同的指針指向相同的資源,直到某個(gè)調(diào)用者試圖修改資源的內(nèi)容時(shí),系統(tǒng)才會(huì)真正復(fù)制一份專(zhuān)用副本(private copy)給該調(diào)用者,而其他調(diào)用者所見(jiàn)到的最初的資源仍然保持不變。
這個(gè)過(guò)程對(duì)其他的調(diào)用者是透明的(transparently)。
此作法的主要優(yōu)點(diǎn)是如果調(diào)用者沒(méi)有修改該資源,就不會(huì)有副本被建立,因此多個(gè)調(diào)用者只是讀取操作是可以共享同一份資源。
寫(xiě)時(shí)拷貝技術(shù)是一種很重要的優(yōu)化手段,核心是懶惰處理實(shí)體資源請(qǐng)求,在多個(gè)實(shí)體資源之間只是共享資源,起初是并不真正實(shí)現(xiàn)資源拷貝,
只有當(dāng)實(shí)體有需要對(duì)資源進(jìn)行修改時(shí)才真正為實(shí)體分配私有資源。但寫(xiě)時(shí)拷貝技術(shù)技術(shù)也有它的優(yōu)點(diǎn)和缺點(diǎn):
1、寫(xiě)時(shí)拷貝技術(shù)可以減少分配和復(fù)制大量資源時(shí)帶來(lái)的瞬間延時(shí),但實(shí)際上是將這種延時(shí)附加到了后續(xù)的操作之中。
2、寫(xiě)時(shí)拷貝技術(shù)可以減少不必要的資源分配。比如fork進(jìn)程時(shí),并不是所有的頁(yè)面都需要復(fù)制,父進(jìn)程的代碼段和只讀數(shù)據(jù)段都不被允許修改,所以無(wú)需復(fù)制。
二、寫(xiě)時(shí)拷貝技術(shù)的應(yīng)用
1、虛擬內(nèi)存管理中的寫(xiě)時(shí)復(fù)制
一般把這種被共享訪(fǎng)問(wèn)的頁(yè)面標(biāo)記為只讀。當(dāng)一個(gè)task試圖向內(nèi)存中寫(xiě)入數(shù)據(jù)時(shí),內(nèi)存管理單元(MMU)拋出一個(gè)異常,內(nèi)核處理該異常時(shí)為該task分配一份物理內(nèi)存并復(fù)制數(shù)據(jù)到此內(nèi)存,
重新向MMU發(fā)出執(zhí)行該task的寫(xiě)操作。
比如Linux的fork()使用寫(xiě)時(shí)拷貝頁(yè)來(lái)實(shí)現(xiàn)新進(jìn)程的創(chuàng)建,它是一種可推遲甚至避免數(shù)據(jù)拷貝的技術(shù),開(kāi)始時(shí)內(nèi)核并不會(huì)復(fù)制整個(gè)地址空間,而是讓父子進(jìn)程共享地址空間,只有在寫(xiě)時(shí)才復(fù)制地址空間,使得父子進(jìn)程都擁有獨(dú)立的地址空間,即資源的復(fù)制是在只有需要寫(xiě)入時(shí)才會(huì)發(fā)生。在此之前都是以讀的方式去和父進(jìn)程共享資源,這樣,在頁(yè)根本不會(huì)被寫(xiě)入的場(chǎng)景下,fork()立即執(zhí)行exec(),無(wú)需對(duì)地址空間進(jìn)行復(fù)制,fork()的實(shí)際開(kāi)銷(xiāo)就是復(fù)制父進(jìn)程的一個(gè)頁(yè)表和為子進(jìn)程創(chuàng)建一個(gè)進(jìn)程描述符,也就是說(shuō)只有當(dāng)進(jìn)程空間中各段的內(nèi)存內(nèi)容發(fā)生變化時(shí),父進(jìn)程才將其內(nèi)容復(fù)制一份傳給子進(jìn)程,大大提高了效率。
2、數(shù)據(jù)存儲(chǔ)中的寫(xiě)時(shí)復(fù)制
Linux等的文件管理系統(tǒng)使用了寫(xiě)時(shí)復(fù)制策略。
舉個(gè)例子,比如我們有個(gè)程序要寫(xiě)文件,不斷地根據(jù)網(wǎng)絡(luò)傳來(lái)的數(shù)據(jù)寫(xiě),如果每一次fwrite或是fprintf都要進(jìn)行一個(gè)磁盤(pán)的I/O操作的話(huà),都簡(jiǎn)直就是性能上巨大的損失,
因此通常的做法是,每次寫(xiě)文件操作都寫(xiě)在特定大小的一塊內(nèi)存中(磁盤(pán)緩存),只有當(dāng)我們關(guān)閉文件時(shí),才寫(xiě)到磁盤(pán)上(這就是為什么如果文件不關(guān)閉,所寫(xiě)的東西會(huì)丟失的原因)
3、軟件應(yīng)用中的寫(xiě)時(shí)復(fù)制
在我們經(jīng)常使用的STL標(biāo)準(zhǔn)模板庫(kù)中的string類(lèi),也是一個(gè)具有寫(xiě)時(shí)才拷貝技術(shù)的類(lèi)。為了提高性能,STL中的許多類(lèi)都采用了寫(xiě)時(shí)拷貝技術(shù)。但是在C++11標(biāo)準(zhǔn)中為了提高并行性取消了這一策略
class String { public: //構(gòu)造函數(shù)(分存內(nèi)存) String(char* tmp) { _Len = strlen(tmp); _Ptr = new char[_Len + 1 + 1]; strcpy(_Ptr, tmp); // 在數(shù)組尾部設(shè)置引用計(jì)數(shù) _Ptr[_Len + 1] = 0; } //析構(gòu)函數(shù) ~String() { //引用計(jì)數(shù)減一 _Ptr[_Len + 1]--; // 引用計(jì)數(shù)為0時(shí),釋放內(nèi)存 if (_Ptr[_Len + 1] == 0) { delete[] _Ptr; } } //拷貝構(gòu)造(共享內(nèi)存) String(string& str) { if (this->_Ptr != str) { //共享內(nèi)存,.data()返回的是將string的類(lèi)型轉(zhuǎn)換成char類(lèi)型的指針 const char *p = str.c_str(); char* pp; strcmp(pp, p); this->_Ptr = pp; this->_Len = str.size(); this->_Ptr[_Len + 1] ++; //引用計(jì)數(shù)加一 } } //對(duì)[]符進(jìn)行重載,對(duì)字符串進(jìn)行操作的時(shí)候,開(kāi)始寫(xiě)時(shí)復(fù)制 char& operator[](unsigned int idx) { if (idx > _Len || _Ptr == 0) { static char nullchar = 0; return nullchar; } //引用計(jì)數(shù)減一 _Ptr[_Len + 1]--; char* tmp = new char[_Len + 1 + 1]; strncpy(tmp, _Ptr, _Len + 1); _Ptr = tmp; // 設(shè)置新的共享內(nèi)存的引用計(jì)數(shù) _Ptr[_Len + 1] = 0; return _Ptr[idx]; } private: int _Len; char* _Ptr; };
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C++實(shí)現(xiàn)LeetCode(97.交織相錯(cuò)的字符串)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(97.交織相錯(cuò)的字符串),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07Visual Studio 2022無(wú)法打開(kāi)源文件的解決方式
這篇文章主要介紹了Visual Studio 2022無(wú)法打開(kāi)源文件的解決方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-01-01使用C語(yǔ)言計(jì)算長(zhǎng)方體的表面積和體積
這篇文章主要給大家介紹了關(guān)于如何使用C語(yǔ)言計(jì)算長(zhǎng)方體的表面積和體積的相關(guān)資料,在C語(yǔ)言中,我們可以使用乘法運(yùn)算符(*)來(lái)進(jìn)行乘法運(yùn)算,并將結(jié)果保存在一個(gè)變量中,需要的朋友可以參考下2023-10-10C語(yǔ)言報(bào)錯(cuò):Format String Vulnerability的多種解決方案
Format String Vulnerability(格式化字符串漏洞)是C語(yǔ)言中常見(jiàn)且嚴(yán)重的安全漏洞之一,它通常在程序使用不受信任的輸入作為格式化字符串時(shí)發(fā)生,本文將詳細(xì)介紹Format String Vulnerability的產(chǎn)生原因,提供多種解決方案,需要的朋友可以參考下2024-06-06C語(yǔ)言實(shí)現(xiàn)單鏈表的快速排序算法
大家好,本篇文章主要講的是C語(yǔ)言實(shí)現(xiàn)單鏈表的快速排序算法,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話(huà)記得收藏一下2022-01-01