C++?RAII在HotSpot?VM中的重要應(yīng)用解析
RAII(Resource Acquisition Is Initialization),也稱為“資源獲取就是初始化”,是C++語言的一種管理資源、避免泄漏的慣用法。C++標(biāo)準(zhǔn)保證任何情況下,已構(gòu)造的對(duì)象最終會(huì)銷毀,即它的析構(gòu)函數(shù)最終會(huì)被調(diào)用。簡(jiǎn)單的說,RAII的做法是使用一個(gè)對(duì)象,在其構(gòu)造時(shí)獲取資源,在對(duì)象生命期控制范圍之下對(duì)資源的訪問始終保持有效,最后在對(duì)象析構(gòu)的時(shí)候釋放資源。
在HotSpot VM中,RAII對(duì)內(nèi)存資源的管理和釋放、明確定義范圍鎖及記錄重要信息等方面起到了非常重要的作用。下面詳細(xì)介紹一下。
1、定義范圍鎖
在HotSpot VM中,整個(gè)系統(tǒng)正確的運(yùn)轉(zhuǎn)需要非常多的鎖,這些鎖很多都是通過RAII技術(shù)來管理的。
舉個(gè)例子,如下:
class MutexLocker { private: pthread_mutex_t *_mtx; public: MutexLocker(pthread_mutex_t *mtx) { if (mtx) { _mtx = mtx; pthread_mutex_lock(_mtx); } } ~MutexLocker() { if (_mtx) pthread_mutex_unlock(_mtx); } };
在類的構(gòu)造和析構(gòu)函數(shù)中對(duì)互斥量進(jìn)行加載和釋放鎖。也就是說,當(dāng)對(duì)象創(chuàng)建的時(shí)候會(huì)自動(dòng)調(diào)用構(gòu)造函數(shù),當(dāng)對(duì)象超出作用域的時(shí)候會(huì)自動(dòng)調(diào)用析構(gòu)函數(shù)。
現(xiàn)在我們通過如上的類將一段代碼保護(hù)起來,防止產(chǎn)生并發(fā)問題:
// 初始化互斥鎖 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; void init(){ MutexLocker locker(&mutex); // 整個(gè)方法都會(huì)在同步鎖的保護(hù)下執(zhí)行 }
我們還可以通過匿名塊來進(jìn)一步細(xì)化鎖控制的范圍。當(dāng)進(jìn)入作用域范圍時(shí),C++會(huì)自動(dòng)調(diào)用MutexLocker的構(gòu)造函數(shù),當(dāng)出了作用域范圍時(shí),會(huì)調(diào)用MutexLocker析構(gòu)函數(shù)。這樣通過類來管理鎖資源,將資源和對(duì)象的生命周期綁定。在Java中有個(gè)類似的、飽受詬病的一種釋放資源的辦法,重寫finalize()方法,由于開發(fā)人員無法對(duì)Java對(duì)象的生命周期進(jìn)行精確控制,而是托管給了Java虛擬機(jī)GC,所以對(duì)象什么時(shí)候回收是一個(gè)未知數(shù),為應(yīng)用程序埋下了一個(gè)定時(shí)炸彈。不過另外一個(gè)類似的語法try-with-resources提倡使用。
在HotSpot VM中,在runtime/mutex.hpp文件中定義了互斥量Mutex,這個(gè)互斥量繼承自Monitor,HotSpot VM內(nèi)部的并發(fā)非常依賴Monitor。在runtime/mutexLocker.hpp文件中定義了MutexLocker、MutexLockerEx等類來控制鎖范圍。
2、管理內(nèi)存資源
管理內(nèi)存資源的一些類有HandleMark、ResourceMark等,HandleMark用來管理句柄,ResourceMark用來管理臨時(shí)使用的內(nèi)存。
HandleMark我在之前已經(jīng)介紹的非常詳細(xì)了,可參考如下文章:
http://www.dbjr.com.cn/article/115051.htm
http://www.dbjr.com.cn/program/297764rfl.htm
ResourceMark的實(shí)現(xiàn)也非常類似。
由于Java類常量池中的字符串、還有一些公共字符串在HotSpot VM中都用Symbol實(shí)例來表示,如果想要看某個(gè)Klass實(shí)例表示的具體的類名稱,我有時(shí)候會(huì)這樣做:
{ ResourceMark rm; Symbol *sym = _klass->name(); const char *klassName = (sym->as_C_string()); // ... }
調(diào)用的as_C_string()函數(shù)實(shí)現(xiàn)如下:
char* Symbol::as_C_string() const { int len = utf8_length(); char* str = (char*) resource_allocate_bytes( (len + 1) * sizeof(char) ); return as_C_string(str, len + 1); } extern char* resource_allocate_bytes(size_t size, AllocFailType alloc_failmode) { ResourceArea* ra = Thread::current()->resource_area(); return ra->allocate_bytes(size, alloc_failmode); }
可以看到從ResourceArea中申請(qǐng)了內(nèi)存,那就必須要記錄,完成調(diào)用之后恢復(fù)調(diào)用之前的樣子,這樣才不會(huì)讓內(nèi)存處在不一致的狀態(tài),從而導(dǎo)致崩潰,所以必須要使用ResourceMark。
3、保存重要信息
閱讀HotSpot VM源代碼的人一定會(huì)對(duì)JavaCalls::call_helper()函數(shù)中的如下這段代碼不陌生:
從HotSpot VM內(nèi)部調(diào)用Java方法時(shí),通常會(huì)調(diào)用到call_helper()函數(shù),所以這也是HotSpot VM調(diào)用Java主類main()方法的關(guān)鍵入口,在這個(gè)函數(shù)中我們能夠看到HandleMark的使用,另外還有一個(gè)JavaCallWrapper,這個(gè)類主要有2個(gè)作用:
(1)管理內(nèi)存資源,在 http://www.dbjr.com.cn/article/75222.htm已經(jīng)詳細(xì)介紹過,這里不再介紹。
(2)記錄Java調(diào)用棧的重要信息,退棧等操作非常依賴這些信息。
變量名叫l(wèi)ink非常貼切,它的起用就是將Java棧連接起來,其大概的實(shí)現(xiàn)過程如下圖所示。
后面我們?cè)诮榻B具體的知識(shí)點(diǎn)時(shí)再詳細(xì)介紹這些內(nèi)容。
RAII技術(shù)被認(rèn)為是C++中管理資源的最佳方法,進(jìn)一步引申,使用RAII技術(shù)也可以實(shí)現(xiàn)安全、簡(jiǎn)潔的狀態(tài)管理,編寫出優(yōu)雅的異常安全的代碼。它利用棧對(duì)象在離開作用域后自動(dòng)析構(gòu)的語言特點(diǎn),將受限資源的生命周期綁定到該對(duì)象上,當(dāng)對(duì)象析構(gòu)時(shí)以達(dá)到自動(dòng)釋放資源的目的。
簡(jiǎn)單而言RAII就是指資源在我們拿到時(shí)就已經(jīng)初始化,一旦不在需要該資源就可以自動(dòng)釋放該資源。
到此這篇關(guān)于C++ RAII在HotSpot VM中的重要應(yīng)用的文章就介紹到這了,更多相關(guān)C++ RAII應(yīng)用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++?primer超詳細(xì)講解關(guān)聯(lián)容器
兩個(gè)主要的關(guān)聯(lián)容器為map和set,map中元素是一些關(guān)鍵字—值對(duì),關(guān)鍵字起索引的作用,值則表示與索引相關(guān)聯(lián)的數(shù)據(jù)。set中每個(gè)元素只包含一個(gè)關(guān)鍵字,set支持高效的關(guān)鍵字查詢操作——檢查一個(gè)給定關(guān)鍵字是否在set中2022-07-07C++中實(shí)現(xiàn)OpenCV圖像分割與分水嶺算法
分水嶺算法是一種常用的圖像區(qū)域分割法,本文主要介紹了OpenCV圖像分割與分水嶺算法,使用C++實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2021-06-06C++超詳細(xì)實(shí)現(xiàn)堆和堆排序過像
堆是計(jì)算機(jī)科學(xué)中一類特殊的數(shù)據(jù)結(jié)構(gòu)的統(tǒng)稱,通常是一個(gè)可以被看做一棵完全二叉樹的數(shù)組對(duì)象。而堆排序是利用堆這種數(shù)據(jù)結(jié)構(gòu)所設(shè)計(jì)的一種排序算法。本文將通過圖片詳細(xì)介紹堆排序,需要的可以參考一下2022-06-06Qt 數(shù)據(jù)庫(kù)QSqlDatabase使用示例
本文主要介紹了Qt數(shù)據(jù)庫(kù)QSqlDatabase使用示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-12-12C語言 數(shù)據(jù)結(jié)構(gòu)之鏈表實(shí)現(xiàn)代碼
這篇文章主要介紹了C語言 數(shù)據(jù)結(jié)構(gòu)之鏈表實(shí)現(xiàn)代碼的相關(guān)資料,需要的朋友可以參考下2016-10-10C++類成員構(gòu)造函數(shù)和析構(gòu)函數(shù)順序示例詳細(xì)講解
這篇文章主要介紹了C++類成員構(gòu)造和析構(gòu)順序示例,看了這個(gè)例子大家就可以明白c++構(gòu)造析構(gòu)的奧秘2013-11-11關(guān)于C++繼承你可能會(huì)忽視的點(diǎn)
繼承是面向?qū)ο笕筇匦灾?有些類與類之間存在特殊的關(guān)系,下面這篇文章主要給大家介紹了關(guān)于C++繼承你可能會(huì)忽視的點(diǎn),文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-02-02