<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          程序也有“腎”,你知道是什么嗎?

          共 2601字,需瀏覽 6分鐘

           ·

          2020-09-19 04:18


          關(guān)注、星標(biāo)公眾號,直達(dá)精彩內(nèi)容

          ID:chiphome-dy

          作者:程世輝

          整理排版:曉宇


          程序的形態(tài)非常之多,不管是可以作為一個操作系統(tǒng),還是作為一個hello world,也不管是作為一個app,還是作為一個嵌入式的固件。程序在本質(zhì)上來說,是函數(shù)代碼與資源的集合體。我們的話題是,程序的資源,而且是程序中第一要素的資源——內(nèi)存。
          如果說程序是一個人,那么骨架可以比喻成程序的架構(gòu),皮肉則是代碼,血液則是內(nèi)存。在程序的運(yùn)行過程當(dāng)中,絕大部分的指令在執(zhí)行與回寫操作,回寫階段都會操作到內(nèi)存,可以說內(nèi)存伴隨著程序執(zhí)行的整個周期,就像是血液始終流轉(zhuǎn)在我們的肉體之中。那么在內(nèi)存中進(jìn)行垃圾回收的程序之“腎”,又是什么呢?
          int* a;int b =2;main(){    static int c;    {        int d = 9;        char* e =  malloc(10);        printf("d=%d\r\n",d);    }}

          這是一段非常簡單的C語言代碼。對于稍微有點(diǎn)基礎(chǔ)的人都知道在這段程序中,每一個變量所占用的內(nèi)存位置。

          首先全局變量與靜態(tài)變量是放在數(shù)據(jù)段(RW段,其中未初始化的放在ZI段,由程序啟動的時候統(tǒng)一清內(nèi)存)比如:a,b,c;

          局部變量放在??臻g中,比如:d,e;

          同時還申請了一段存放于堆的內(nèi)存,但是代碼中并未使用free函數(shù)進(jìn)行釋放。

          根據(jù)內(nèi)存的特性我們知道,對于a,b,c等數(shù)據(jù)段的變量,它們是常住內(nèi)存的,生命周期是永久的。對于棧里面的局部變量d,e。它們的生命周期僅僅在“{}”之內(nèi),伴隨著棧操作的push以及pop指令,創(chuàng)建和消亡。

          程序中當(dāng)e消亡在花括號外后,在堆中申請的內(nèi)存就失去了指針對它的指向?qū)е铝藘?nèi)存泄漏。如果是在簡單的程序中,這樣的情況處理起來還是比較簡單的,我們只要在程序后面采用free函數(shù)釋放內(nèi)存就可以。

          但是如果在擁有復(fù)雜的邏輯程序,這樣動態(tài)申請的內(nèi)存就需要花不少心思去管理。這個就是為啥很多java之類的高級語言在制作教程的時候都會在與C/C++比較時經(jīng)常強(qiáng)調(diào),java沒有指針并且擁有垃圾自動回收機(jī)制,會顯得更加安全,程序的健壯性更加容易得到保證。(當(dāng)然C/C++也可以寫出健壯的程序,只是有些東西沒那么方便)。這種可以自動幫助程序進(jìn)行內(nèi)存自動垃圾回收的機(jī)制就是程序的“腎”了。

          那么為啥C/C++到現(xiàn)在都不支持垃圾自動回收機(jī)制呢?我們可以從自動垃圾回收機(jī)制的原理去尋到答案。首先說一下自動垃圾回收的判定算法,一般常用的是兩個:

          、引用計數(shù)法。

          所謂的引用計數(shù)法,顧名思義就是在內(nèi)存的描述結(jié)構(gòu)體內(nèi)部采用一個計數(shù)變量進(jìn)行計數(shù)。每當(dāng)有指針或者引用指向該內(nèi)存塊的時候,該內(nèi)存塊的描述結(jié)構(gòu)體內(nèi)部的計數(shù)器就遞增。當(dāng)指針或者引用被釋放或者改變的時候就遞減。當(dāng)內(nèi)存塊的計數(shù)遞減到0的時候,就可以釋放回收該內(nèi)存塊了。

          引用計數(shù)法,應(yīng)該說是最簡單實(shí)現(xiàn)內(nèi)存可回收判定的算法。采用該算法實(shí)現(xiàn)自動回收機(jī)制的典型的有apple開發(fā)平臺Object-C支持的ARC機(jī)制。這種自動垃圾回收算法的實(shí)現(xiàn)有一個依賴和一個缺點(diǎn)。它的依賴就是需要編譯器自動插入計數(shù)代碼。

          想OC在xcode平臺開發(fā)程序,它的編譯環(huán)境會自動地插入手動進(jìn)行計數(shù)的函數(shù)retain,release這樣的語句。所以這個實(shí)現(xiàn)自動垃圾回收的本質(zhì)還是讓編譯器做手動該做的事情而已。

          如果說C也需要實(shí)現(xiàn)類似的方式進(jìn)行自動回收,那么就需要對編譯器的預(yù)處理過程進(jìn)行改造,并且在內(nèi)存申請和釋放的庫函數(shù)之上維護(hù)一個內(nèi)存的監(jiān)控結(jié)構(gòu),去給內(nèi)存塊做計數(shù)。

          同時引用計數(shù)法法有一個非常大的缺點(diǎn),就是循環(huán)引用會導(dǎo)致內(nèi)存泄漏。如下代碼:

          fun(){    A* a = [ A new];    A* a1 = a;    B* b = [B new];    B* b1 =  b;              a->b = b;             b ->a = a;}

          當(dāng)函數(shù)執(zhí)行完畢,a與b相互引用。但是在棧中以及在數(shù)據(jù)段中已經(jīng)沒有指針可以訪問到a與b的對象本身。也就是說程序已經(jīng)失去了這兩塊內(nèi)存的訪問權(quán),但是它們兩者又相互指向,導(dǎo)致內(nèi)存的計數(shù)無法歸零。所以一直不能釋放,導(dǎo)致了內(nèi)存泄漏,形成了垃圾。

          二、可達(dá)性分析法。

          可達(dá)性分析法,顧名思義就是分析內(nèi)存程序能否可以“達(dá)到”。也就是分析程序是否有失去對于內(nèi)存的訪問權(quán)。程序在運(yùn)行狀態(tài)中,內(nèi)存時刻處于變化之中,猶如人體的血液流動不止。但是不管在任何時刻,我們的程序一定可以訪問的內(nèi)存大概有2個類別:

          1、數(shù)據(jù)段,也就是全局變量與靜態(tài)變量。

          2、??臻g中未釋放的變量也就是當(dāng)前入棧的動態(tài)局部變量。

          可達(dá)性分析法需要依賴于Runtime,也就是運(yùn)行時環(huán)境,它們時刻監(jiān)控著上面兩個大類內(nèi)存中的指針變量或者引用,并且周期性地對這些指針或者引用的指向進(jìn)行遍歷,并且是遞歸逐級地往下遍歷。整體而言是在遍歷一個以這兩大類內(nèi)存中的指針變量和引用為入口的圖。只要能夠遍歷到的內(nèi)存塊就可以進(jìn)行可達(dá)性的標(biāo)志。

          當(dāng)程序進(jìn)入垃圾回收周期,它會遍歷已經(jīng)分配的所有內(nèi)存,如果訪問到的內(nèi)存塊擁有可達(dá)性標(biāo)志,那么則跳過。如果沒有可達(dá)性標(biāo)志,則可以釋放回收。這樣就可以避免類似引用計數(shù)算相互引用導(dǎo)致不歸零,但是不可達(dá)卻又不釋放的問題。如下圖,藍(lán)色內(nèi)存塊是會被回收的。

          然而,可達(dá)性分析算法是需要依賴于運(yùn)行時環(huán)境的,也就是類似java那樣的虛擬機(jī)。所以目前C/C++之類的語言還無法支持這種自動垃圾回收的判定算法。

          所以說了那么多,我們對于這些程序語言的一個診斷是:

          OC:apple給它換了腎,但是腎不好,不過總體無礙。

          java:腎很好啊。

          C/C++:沒有腎的,需要程序員幫他做“腎透析”。

          那么像C/C++這么好的語言,我們能夠給它一個“腎”,讓它過上更加健康的生活嗎?

          答案是有的。

          推薦閱讀:


          嵌入式編程專輯
          Linux 學(xué)習(xí)專輯
          C/C++編程專輯
          Qt進(jìn)階學(xué)習(xí)專輯
          關(guān)注微信公眾號『技術(shù)讓夢想更偉大』,后臺回復(fù)“m”查看更多內(nèi)容,回復(fù)“加群”加入技術(shù)交流群。

          長按前往圖中包含的公眾號關(guān)注

          瀏覽 65
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  a视频在线播放 | 熟妇三区| 91丨豆花丨国产熟女 熟女 | 亚洲三级片视频 | 欧美日韩在线观看成人 |