亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频

蟲蟲首頁| 資源下載| 資源專輯| 精品軟件
登錄| 注冊

您現在的位置是:首頁 > 技術閱讀 >  編程思考:對象生命周期的問題

編程思考:對象生命周期的問題

時間:2024-02-12




前情提要


只要寫過 c/c++ 的項目的童鞋應該對對象生命周期的問題記憶猶新。怕有人還不理解這個問題,筆者先介紹下什么是生命周期的問題?

一個 struct 結構體生命周期分為三個步驟:

  1. 出生:malloc 分配結構體內存,并且初始化;
  2. 使用:這個就是對內存的常規使用了;
  3. 銷毀:free 釋放這個內存塊;

最典型結構體“生命周期”問題的場景就是:你在使用對象正嗨的時候,被人偷偷把對象銷毀了。舉個例子:

  • 12:00 時刻:ObjectA 內存 malloc 出來,地址為 0x12345 ;
  • 12:10 時刻:ObjectA 內存地址 0x12345 釋放了;
  • 12:12 時刻:程序猿小明拿到了 ObjectA 的地址 0x12345 ,準備大干一場(但他并不知道的是,這個 ObjectA 結構體已經結束了生命,0x12345 地址已經被釋放了)于是,踩內存了,全劇終;

生命周期問題的維度


一般來講,生命周期的問題其實有兩個方面:

  • 第一個是結構體本身內存的生命周期 ;
  • 第二個是結構體對象管理的資源( 比如資源句柄 );

 1   結構體本身內存


對象結構體本身的生命周期這個很容易理解,這個就是內存的分配和釋放。

// 步驟一:分配
obj_addr = malloc(...);
// 步驟二:使用 ...
// 步驟三:釋放
free(obj_addr);

如果違反了這條(使用了已經釋放的內存塊),就會發生踩內存,野指針,未定義地址等一系列奇異事件。如果沒正確釋放,那么就是內存泄漏。


 2   對象管理的資源


這個也很容易理解,比如一個代表 fd_t 的結構體,里面有一個整型字段,代表這個結構體管理的一個文件句柄。當 fd_t 結構體內存被釋放的時候,它管理的文件句柄 sys_fd 也是需要 close 的。

struct fd_t {
    int sys_fd; // 系統句柄(這個需要在合適的時機釋放)
    struct list_head list; // 鏈表掛接件
    //...
};

如果違反了這條(使用釋放了的資源,比如句柄),那么就會出現 bad descriptor 等一系列情況。


怎么才能解決生命周期的問題?


生命周期的問題是每個程序猿都可能遇到的,只要程序中涉及到資源的創建、使用、釋放,這三個過程,那么生命周期的問題就是你必經之路,這是一個通用的問題

上面我們提到生命周期問題的兩個維度,那么解決也是這兩個維度的針對性解決。遵守兩個原則

  1. 對象在有人使用的時候不能釋放;
  2. 對象不僅要釋放自身內存還要釋放管理的資源

思考下:你在編程的時候,怎么處理的?

下面我從 c 這種底層語言,還有 Go 這種自帶 GC 的語言對比出發,來體驗下不同語言下的生命周期的問題怎么解決。


c 編程的慣例


c 怎么才能保證內存的安全,資源的安全釋放呢?

以下面的場景舉例:

  1. 現在有一個 fd_t 的 list 鏈表,為了保護這個鏈表,用一個互斥鎖來保護 ;
  2. 創建 fd_t 的時候,需要添加進 list(添加會加互斥鎖);
  3. 正常使用的時候,會遍歷 list ,取合適的元素使用;
  4. fd_t 銷毀的時候,會從全局鏈表中摘除;

首先,list 鏈表的并發安全可以用互斥鎖來解決,但是怎么保證你取出來元素之后,還在處理的時候,一直是安全的呢(不被釋放)?

你可能會自然想到一個思路:全程在鎖內不就可以了。

確實如此,對象的創建,使用,刪除,全程用鎖保護,確實可以解決這個問題。但是鎖度變得非常大,在現實生產環境的編程中,很少見。

其實,解決資源釋放的場景,有一個通用的技術:引用計數。 wiki 上的解釋:

引用計數是計算機編程語言中的一種內存管理技術,是指將資源(可以是對象、內存或磁盤空間等等)的被引用次數保存起來,當被引用次數變為零時就將其釋放的過程。使用引用計數技術可以實現自動資源管理的目的。

引用計數是一種通用的資源管理技術,簡述引用計數用法:

  1. 資源初始化的時候,計數為 1 ;
  2. 就是在資源獲取的時候,對資源計數加 1 ;
  3. 資源使用完成的時候,對資源計數減 1 ;
  4. 計數為 0 的時候,走釋放流程 ;

這樣,只需要用戶對資源的使用上遵守一個規則:獲取的時候,計數加 1,處理完了,計數減 1 ,就能保證不會有問題。因為在你使用期間,不管別人怎么減,都不可能會到 0 。

思考下:引用計數有什么缺點呢?

  1. 第一個問題,非常容易出錯,加減引用一定要配對,一旦有些地方多加了,或者多減了,就會引發資源問題。要么就是泄漏,要么就是使用釋放了的資源;
  2. 第二個問題,在于流程上變復雜了,因為計數為 0 的地方點變得不確定了。可能會出現在讀元素的流程上,走釋放流程;

以上兩點,其實對程序猿的能力、細致提出了很高的要求。


Go 就厲害了


引用計數是通用的技術,適用于所有的語言。筆者在寫 Go 的時候就用引用計數來解決過資源釋放的問題。

但后來發現,Go 語言其實可以把代碼寫的更簡單,Go 的創建則從兩個的角度解決了對象生命周期的問題:

第一,根本不讓用戶釋放內存;

Go 的內存,程序猿只能觸發分配,無法主動釋放。釋放內存的動作完全交給了后臺 GC 流程。這就很好的解決了第一個問題,由于不讓粗心的程序猿參與到資源的管理中,內存資源的管理完全由框架管理(框架強,則我強,嘿嘿),根本就不用擔心會被程序猿用到生命終結的內存塊。

第二,提供析構回調函數機制;

上面說了,GC 能夠保證內存結構體本身的安全性,但是一些句柄資源的釋放卻無法通過上面保證,怎么辦?

Go 提供了一個非常好的辦法:設置析構函數。使用 runtime.SetFinalizer 來設置,將一個對象的地址和一個析構函數綁定起來,并且注冊到框架里。當對象被 GC 的時候,析構函數將會被框架調用,程序猿則可以把資源釋放的邏輯寫到析構函數中,這樣就配合上了呀,就能保證:在對象永遠不能被程序猿摸到的前提下,調用了析構函數,從而完成資源釋放


 1   生命結束的回調


函數原型:

func SetFinalizer(obj interface{}, finalizer interface{})

參數解析:

  • 參數 obj 必須是指針類型
  • 參數 finalizer 是一個函數,參數為 obj 的類型,無返回值

函數調用 runtime.SetFinalizerobjfinalizer 關聯起來。對象 obj 被 Gc 的時候,Go 會自動調用 finalizer 函數,并且 obj 作為參數傳入。

就這樣,關于生命周期的問題,在 Go 里面就非常優雅的解決了,對象內存釋放交給了 Gc,資源釋放交給了 finalizer ,程序猿又可以躺好了。


擴展思考


c++ 和 Python 這兩種語言又是怎么解決內存的生命周期,還有資源的安全釋放呢?

提示:這兩種語言都有構造函數和析構函數,但各有不同。這個問題留給讀者朋友思考。

  • c++ 有構造函數和析構函數,也很方便,但是 c++ 的類卻是非常復雜的。且 c++ 是沒有 GC 的,內存釋放的動作還是交給了程序猿,所以在 c++ 編程中,引用計數技術還是大量使用的;
  • python 是一個自帶 GC ,并且提供構造和析構函數的。所以 python 的使用,程序猿完全不管內存釋放,資源釋放則只需要定義在類的析構函數里即可;

總結


  1. 生命周期的問題是老大難的問題,分為結構內存的安全釋放,內部管理資源的安全釋放兩個維度;
  2. c/c++ 大量采用引用計數技術來完成對資源的安全釋放;
  3. 引用計數的難點在于加減計數的配套使用,并且釋放的現場不確定
  4. Go 通過內存自動 Gc ,且提供析構函數綁定到對象地址的方法,從而完美解決了對象生命周期的問題;
  5. runtime.SetFinalizer 替代引用計數的使用,太香了;

后記


open  一個文件得到句柄 fd,緊接 unlink  這個文件,此時,還可用 fd 來正常讀寫文件。直到 close  這個文件的時候,這個文件才會永遠的消失。你能猜到其中原理嗎?

~完~

往期推薦



往期推薦



自制文件系統 —— 03 Go實戰:hello world 的文件系統

假如 Go 能說話,聽聽 GMP 的心聲

存儲基礎 — 文件描述符 fd 究竟是什么?

深度剖析 Linux cp 的秘密


堅持思考,方向比努力更重要。關注我:奇伢云存儲


亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频
老鸭窝91久久精品色噜噜导演| 久久精品国产2020观看福利| 国产精品高潮粉嫩av| 欧美日韩一二三四五区| 国产精品日韩二区| 伊人婷婷欧美激情| 亚洲制服少妇| 老鸭窝毛片一区二区三区| 欧美日韩在线一区二区| 国产一区美女| 亚洲一区二区三区影院| 欧美国产日本| 红桃视频国产精品| 午夜国产精品影院在线观看| 麻豆成人91精品二区三区| 国产精品第13页| 亚洲精品久久嫩草网站秘色| 久久久久9999亚洲精品| 午夜视频一区在线观看| 欧美日韩精品一本二本三本| 国产亚洲精品一区二区| 亚洲欧美视频在线观看视频| 欧美性色视频在线| 99re6这里只有精品| 欧美电影在线播放| 在线电影一区| 久久综合国产精品| 国语精品中文字幕| 欧美在线三区| 国内成+人亚洲| 久久精品99无色码中文字幕| 国产精品欧美久久久久无广告| 亚洲深夜福利网站| 国产精品va| 午夜国产精品视频免费体验区| 欧美日韩国产成人在线91| 亚洲高清资源| 欧美黄色一级视频| 亚洲精品在线视频观看| 欧美日韩综合视频网址| 亚洲美女电影在线| 欧美精品在线一区二区| 99国产精品视频免费观看| 欧美日韩三级在线| 一区二区高清在线| 国产精品美女一区二区| 欧美在线精品一区| 亚洲第一区在线观看| 欧美激情中文不卡| 亚洲一区二区三区四区在线观看| 国产精品日韩精品欧美精品| 久久精品欧洲| 99re热精品| 国产精品亚洲激情| 久久阴道视频| 日韩亚洲在线| 国产精品网站视频| 久久精品人人做人人爽电影蜜月 | 榴莲视频成人在线观看| 亚洲国产精品va在线看黑人动漫| 欧美成人中文字幕| 亚洲一区日韩| 亚洲国产91精品在线观看| 欧美日韩性视频在线| 欧美一区1区三区3区公司| 激情国产一区二区| 欧美性猛交99久久久久99按摩| 欧美一区二区日韩一区二区| 亚洲国产婷婷| 国产女主播一区| 欧美片第一页| 久久频这里精品99香蕉| 在线综合亚洲| 91久久极品少妇xxxxⅹ软件| 国产欧美丝祙| 欧美日韩国产在线看| 久久久久www| 亚洲视频图片小说| 亚洲人体1000| 影音欧美亚洲| 国产亚洲精品激情久久| 欧美午夜免费影院| 欧美第一黄色网| 久久婷婷综合激情| 欧美一区二区成人| 一道本一区二区| 亚洲二区免费| 激情五月综合色婷婷一区二区| 国产精品你懂的在线| 欧美日韩亚洲网| 免费视频一区| 蜜桃久久av一区| 久久香蕉国产线看观看网| 性色av香蕉一区二区| 亚洲午夜精品久久| 亚洲午夜伦理| 亚洲性线免费观看视频成熟| 一区二区久久| 在线亚洲欧美视频| 一本色道久久综合亚洲精品婷婷| 亚洲国产天堂久久国产91| 亚洲电影免费在线| 亚洲国产成人久久综合| 亚洲国产成人不卡| 亚洲国产一区二区在线| 亚洲高清三级视频| 亚洲精品视频免费| 99热免费精品在线观看| 中文日韩在线视频| 亚洲欧美日韩在线| 久久aⅴ国产紧身牛仔裤| 欧美亚洲视频| 久久久一区二区三区| 美国三级日本三级久久99| 久久野战av| 欧美女同在线视频| 国产精品午夜电影| 精品成人一区| 日韩一级大片在线| 午夜精品视频在线| 久久露脸国产精品| 欧美久久影院| 国产精品国内视频| 国产一区二区日韩精品欧美精品| 国产一区二区中文字幕免费看| 在线观看中文字幕亚洲| 9人人澡人人爽人人精品| 亚洲女女女同性video| 久久国产精品久久久久久电车| 久久久久免费| 欧美久久在线| 国产亚洲视频在线| 亚洲国产另类精品专区| 亚洲少妇在线| 久久综合福利| 国产精品一区二区久久国产| 伊人婷婷欧美激情| 亚洲永久免费精品| 免费观看亚洲视频大全| 国产精品视频区| 亚洲精品久久久久中文字幕欢迎你 | 久久经典综合| 欧美日韩成人一区| 国产日韩在线视频| av72成人在线| 麻豆久久精品| 国产欧美日韩综合精品二区| 亚洲精品专区| 久久亚洲春色中文字幕久久久| 欧美性开放视频| 午夜精品视频在线观看| 亚洲高清在线视频| 欧美国产亚洲另类动漫| 亚洲二区免费| 亚洲国产精品久久91精品| 国产视频不卡| 欧美精品三级日韩久久| 欧美大成色www永久网站婷| 久久国产精品亚洲va麻豆| 欧美在线亚洲一区| 性高湖久久久久久久久| 亚洲激情校园春色| 亚洲国产精品成人综合| 欧美天堂亚洲电影院在线播放 | 亚洲永久免费| 欧美aⅴ99久久黑人专区| 免费91麻豆精品国产自产在线观看| 亚洲视频在线一区观看| 欧美日韩亚洲一区二| 好吊视频一区二区三区四区| 亚洲美女少妇无套啪啪呻吟| 久久综合激情| 国产精品免费久久久久久| 亚洲人体一区| 开心色5月久久精品| 国产一区二区三区不卡在线观看 | 久久精品视频在线| 国产九色精品成人porny| 亚洲国产精品悠悠久久琪琪| 欧美一区二区三区四区在线观看| 国产精品一区一区| 亚洲欧美成人网| 国产伦精品一区二区三区| 香蕉久久夜色精品国产| 国产精品视频网站| 性欧美长视频| 黄色成人91| 男女激情久久| 99re在线精品| 国产精品美女一区二区在线观看| 香蕉久久夜色精品国产| 娇妻被交换粗又大又硬视频欧美| 麻豆视频一区二区| 日韩视频在线一区二区三区| 国产精品福利网站| 久久免费精品视频| av不卡在线| 国产综合香蕉五月婷在线| 蜜臀久久99精品久久久画质超高清 | 一区国产精品|