Java 內(nèi)存模式

Java 內(nèi)存模式

Java內(nèi)存模型規(guī)范了Java虛擬機(jī)與計(jì)算機(jī)內(nèi)存是如何協(xié)同工作的。Java虛擬機(jī)是一個(gè)完整的計(jì)算機(jī)的一個(gè)模型,因此這個(gè)模型自然也包含一個(gè)內(nèi)存模型——又稱為Java內(nèi)存模型桌吃。

如果你想設(shè)計(jì)表現(xiàn)良好的并發(fā)程序,理解Java內(nèi)存模型是非常重要的。Java內(nèi)存模型規(guī)定了如何和何時(shí)可以看到由其他線程修改過后的共享變量的值筐咧,以及在必須時(shí)如何同步的訪問共享變量

原始的Java內(nèi)存模型存在一些不足仔掸,因此Java內(nèi)存模型在Java1.5時(shí)被重新修訂脆贵。這個(gè)版本的Java內(nèi)存模型在Java8中人在使用。

Java內(nèi)存模型內(nèi)部原理

Java內(nèi)存模型把Java虛擬機(jī)內(nèi)部劃分為線程棧和堆起暮。這張圖演示了Java內(nèi)存模型的邏輯視圖

image

每一個(gè)運(yùn)行在Java虛擬機(jī)里的線程都擁有自己的線程棧卖氨。這個(gè)線程棧包含了這個(gè)線程調(diào)用的方法當(dāng)前執(zhí)行點(diǎn)相關(guān)的信息。一個(gè)線程僅能訪問自己的線程棧负懦。一個(gè)線程創(chuàng)建的本地變量對(duì)其它線程不可見筒捺,僅自己可見。即使兩個(gè)線程執(zhí)行同樣的代碼纸厉,這兩個(gè)線程任然在在自己的線程棧中的代碼來創(chuàng)建本地變量系吭。因此,每個(gè)線程擁有每個(gè)本地變量的獨(dú)有版本残腌。

線程堆棧還包含執(zhí)行每個(gè)方法的所有局部變量(調(diào)用堆棧上的所有方法)村斟。 一個(gè)線程只能訪問它自己的線程堆棧。 線程所創(chuàng)建的局部變量對(duì)于所有其他線程都是不可見的抛猫,而不是創(chuàng)建線程的線程蟆盹。 即使兩個(gè)線程執(zhí)行完全相同的代碼,兩個(gè)線程仍然會(huì)在每個(gè)自己的線程堆棧中創(chuàng)建該代碼的局部變量闺金。 因此逾滥,每個(gè)線程都有自己的每個(gè)局部變量的版本。

原始類型(boolean败匹,byte寨昙,short,char掀亩,int舔哪,long,float槽棍,double)的所有局部變量都完全存儲(chǔ)在線程堆棧上捉蚤,因此對(duì)其他線程不可見。 一個(gè)線程可以將一個(gè)原始類型變量的副本傳遞給另一個(gè)線程炼七,但是它不能共享原始局部變量本身缆巧。

該堆包含您的Java應(yīng)用程序中創(chuàng)建的所有對(duì)象,無論創(chuàng)建對(duì)象的線程如何豌拙。 這包括基本類型的對(duì)象版本(例如陕悬,字節(jié),整數(shù)按傅,長(zhǎng)等)捉超。 如果對(duì)象被創(chuàng)建并分配給局部變量胧卤,或者創(chuàng)建為另一個(gè)對(duì)象的成員變量,對(duì)象仍然存儲(chǔ)在堆上拼岳,這并不重要灌侣。

下面的圖示出了存儲(chǔ)在線程堆棧上的調(diào)用堆棧和局部變量以及存儲(chǔ)在堆上的對(duì)象:

image

局部變量可能是一個(gè)原始類型,在這種情況下裂问,它完全保留在線程棧上侧啼。

局部變量也可以是對(duì)象的引用。在這種情況下堪簿,引用(局部變量)存儲(chǔ)在線程堆棧上痊乾,但對(duì)象本身存儲(chǔ)在堆上。

對(duì)象可能包含方法椭更,這些方法可能包含局部變量哪审。這些局部變量也存儲(chǔ)在線程堆棧中,即使該方法所屬的對(duì)象存儲(chǔ)在堆上虑瀑。

對(duì)象的成員變量與對(duì)象本身一起存儲(chǔ)在堆上湿滓。當(dāng)成員變量是原始類型,并且它是對(duì)對(duì)象的引用時(shí)舌狗,這是真的叽奥。

靜態(tài)類變量也與類定義一起存儲(chǔ)在堆上。

所有對(duì)該對(duì)象引用的線程都可以訪問堆上的對(duì)象痛侍。當(dāng)線程訪問對(duì)象時(shí)朝氓,它也可以訪問對(duì)象的成員變量。如果兩個(gè)線程同時(shí)在同一個(gè)對(duì)象上調(diào)用一個(gè)方法主届,那么它們都可以訪問對(duì)象的成員變量赵哲,但每個(gè)線程都有自己的局部變量副本。

[圖片上傳失敗...(image-f8c969-1529157793436)]

兩個(gè)線程有??一組局部變量君丁。局部變量(Local Variable 2)之一指向堆上的共享對(duì)象(對(duì)象3)枫夺。兩個(gè)線程各自對(duì)同一個(gè)對(duì)象有不同的引用。它們的引用是局部變量绘闷,因此存儲(chǔ)在每個(gè)線程的線程堆棧(每個(gè))上橡庞。兩個(gè)不同的引用指向堆上的同一個(gè)對(duì)象。

注意共享對(duì)象(Object 3)如何引用Object 2和Object 4作為成員變量(由Object 3到Object 2和Object 4的箭頭所示)簸喂。通過對(duì)象3中的這些成員變量引用毙死,兩個(gè)線程可以訪問對(duì)象2和對(duì)象4燎潮。

該圖還顯示了一個(gè)局部變量喻鳄,指向堆上的兩個(gè)不同對(duì)象。在這種情況下确封,引用指向兩個(gè)不同的對(duì)象(對(duì)象1和對(duì)象5)除呵,而不是相同的對(duì)象再菊。在理論上,如果兩個(gè)線程都對(duì)兩個(gè)對(duì)象都引用颜曾,則兩個(gè)線程都可以訪問對(duì)象1和對(duì)象5纠拔。但是在上圖中,每個(gè)線程只有一個(gè)對(duì)兩個(gè)對(duì)象之一的引用泛豪。

那么稠诲,什么樣的Java代碼可以導(dǎo)致上述內(nèi)存圖?那么代碼如下代碼一樣簡(jiǎn)單:

public class MyRunnable implements Runnable() {

    public void run() {
        methodOne();
    }

    public void methodOne() {
        int localVariable1 = 45;

        MySharedObject localVariable2 =
            MySharedObject.sharedInstance;

        //... do more with local variables.

        methodTwo();
    }

    public void methodTwo() {
        Integer localVariable1 = new Integer(99);

        //... do more with local variable.
    }
}

public class MySharedObject {

    //static variable pointing to instance of MySharedObject

    public static final MySharedObject sharedInstance =
        new MySharedObject();


    //member variables pointing to two objects on the heap

    public Integer object2 = new Integer(22);
    public Integer object4 = new Integer(44);

    public long member1 = 12345;
    public long member1 = 67890;
}

如果兩個(gè)線程正在執(zhí)行run()方法诡曙,那么前面顯示的圖將是結(jié)果臀叙。 run()方法調(diào)用methodOne()和methodOne()調(diào)用methodTwo()。

methodOne()聲明一個(gè)原始局部變量(int類型的localVariable1)和一個(gè)作為對(duì)象引用(localVariable2)的局部變量价卤。

執(zhí)行methodOne()的每個(gè)線程將在它們各自的線程堆棧上創(chuàng)建自己的localVariable1和localVariable2副本劝萤。 localVariable1變量將完全分開,只能生活在每個(gè)線程的線程堆棧上慎璧。一個(gè)線程無法看到另一個(gè)線程對(duì)其localVariable1的副本進(jìn)行了什么更改床嫌。

執(zhí)行methodOne()的每個(gè)線程也將創(chuàng)建自己的localVariable2副本。然而胸私,localVariable2的兩個(gè)不同的副本都最終指向堆上的同一個(gè)對(duì)象厌处。代碼將localVariable2設(shè)置為指向靜態(tài)變量引用的對(duì)象。靜態(tài)變量只有一個(gè)副本岁疼,該副本存儲(chǔ)在堆上嘱蛋。因此,localVariable2的兩個(gè)副本都指向靜態(tài)變量指向的MySharedObject的同一個(gè)實(shí)例五续。 MySharedObject實(shí)例也存儲(chǔ)在堆上洒敏。它對(duì)應(yīng)于上圖中的對(duì)象3。

注意MySharedObject類如何包含兩個(gè)成員變量疙驾。成員變量本身與對(duì)象一起存儲(chǔ)在堆上凶伙。兩個(gè)成員變量指向另外兩個(gè)Integer對(duì)象。這些整數(shù)對(duì)象對(duì)應(yīng)于上圖中的對(duì)象2和對(duì)象4它碎。

還要注意methodTwo()如何創(chuàng)建一個(gè)名為localVariable1的局部變量函荣。這個(gè)局部變量是一個(gè)Integer對(duì)象的對(duì)象引用。該方法將localVariable1引用設(shè)置為指向一個(gè)新的整數(shù)實(shí)例扳肛。 localVariable1引用將被存儲(chǔ)在執(zhí)行methodTwo()的每個(gè)線程的一個(gè)副本中傻挂。實(shí)例化的兩個(gè)Integer對(duì)象將被存儲(chǔ)在堆上,但是由于該方法在每次執(zhí)行該方法時(shí)都會(huì)創(chuàng)建一個(gè)新的Integer對(duì)象挖息,所以執(zhí)行此方法的兩個(gè)線程將創(chuàng)建單獨(dú)的Integer實(shí)例金拒。 methodTwo()中創(chuàng)建的Integer對(duì)象對(duì)應(yīng)于上圖中的Object 1和Object 5。

還要注意類型為long的類MySharedObject中的兩個(gè)成員變量,這是一個(gè)原始類型绪抛。由于這些變量是成員變量资铡,它們?nèi)匀慌c對(duì)象一起存儲(chǔ)在堆上。只有局部變量存儲(chǔ)在線程堆棧中

硬件內(nèi)存架構(gòu)

現(xiàn)代硬件內(nèi)存架構(gòu)與內(nèi)部Java內(nèi)存模型有所不同幢码。 了解硬件內(nèi)存架構(gòu)也很重要笤休,以了解Java內(nèi)存模型的工作原理。 本節(jié)介紹常見的硬件內(nèi)存架構(gòu)症副,后面的部分將介紹Java內(nèi)存模型的工作原理店雅。

以下是現(xiàn)代計(jì)算機(jī)硬件架構(gòu)的簡(jiǎn)化圖:

image

現(xiàn)代計(jì)算機(jī)通常有2個(gè)或更多的CPU。其中一些CPU也可能有多個(gè)內(nèi)核贞铣。關(guān)鍵是底洗,在具有2個(gè)或更多個(gè)CPU的現(xiàn)代計(jì)算機(jī)上,可以同時(shí)運(yùn)行多個(gè)線程咕娄。每個(gè)CPU都可以在任何給定的時(shí)間運(yùn)行一個(gè)線程亥揖。這意味著如果您的Java應(yīng)用程序是多線程的,則每個(gè)CPU可能會(huì)在Java應(yīng)用程序中同時(shí)(同時(shí))運(yùn)行一個(gè)線程圣勒。

每個(gè)CPU都包含一組本質(zhì)上是CPU內(nèi)存的寄存器费变。 CPU可以在這些寄存器上執(zhí)行的操作比在主存儲(chǔ)器中對(duì)變量執(zhí)行的操作要快得多。這是因?yàn)镃PU可以訪問這些寄存器比訪問主內(nèi)存的速度快得多圣贸。

每個(gè)CPU也可以具有CPU緩存存儲(chǔ)器層挚歧。事實(shí)上,大多數(shù)現(xiàn)代CPU具有一定大小的緩存內(nèi)存層吁峻。 CPU可以比主存儲(chǔ)器快速訪問其緩存滑负,但通常不能像訪問其內(nèi)部寄存器一樣快。因此用含,CPU緩存內(nèi)存位于內(nèi)部寄存器和主存儲(chǔ)器的速度之間矮慕。某些CPU可能有多個(gè)緩存層(1級(jí)和2級(jí)),但是要了解Java內(nèi)存模型如何與內(nèi)存進(jìn)行交互啄骇,這并不重要痴鳄。重要的是知道CPU可以具有某種緩存內(nèi)存層。

計(jì)算機(jī)還包含主存儲(chǔ)區(qū)(RAM)缸夹。所有CPU都可以訪問主存儲(chǔ)器痪寻。主存儲(chǔ)區(qū)通常遠(yuǎn)大于CPU的高速緩沖存儲(chǔ)器。

通常虽惭,當(dāng)CPU需要訪問主存儲(chǔ)器時(shí)橡类,它會(huì)將主存儲(chǔ)器的一部分讀入其CPU緩存。甚至可以將部分高速緩存讀入其內(nèi)部寄存器芽唇,然后對(duì)其執(zhí)行操作顾画。當(dāng)CPU需要將結(jié)果寫回主內(nèi)存時(shí),它將從內(nèi)部寄存器中將值刷新到高速緩沖存儲(chǔ)器,并在某些時(shí)候?qū)⒅邓⑿碌街鞔鎯?chǔ)器亲雪。

當(dāng)CPU需要在高速緩沖存儲(chǔ)器中存儲(chǔ)其他內(nèi)容時(shí),存儲(chǔ)在高速緩沖存儲(chǔ)器中的值通常被刷新回主存儲(chǔ)器疚膊。 CPU緩存一次可以將數(shù)據(jù)寫入其內(nèi)存的一部分义辕,并一次刷新其內(nèi)存的一部分。每次更新時(shí)寓盗,它不必讀取/寫入完整的緩存灌砖。通常,緩存在被稱為“高速緩存行”的更小的存儲(chǔ)塊中被更新傀蚌』裕可以將一個(gè)或多個(gè)高速緩存行讀入高速緩沖存儲(chǔ)器,并且可以將一個(gè)或多個(gè)高速緩存線重新刷回主存儲(chǔ)器善炫。

Java內(nèi)存模型與硬件內(nèi)存架構(gòu)之間的聯(lián)系

如前所述撩幽,Java內(nèi)存模型和硬件內(nèi)存架構(gòu)是不同的。 硬件內(nèi)存架構(gòu)不區(qū)分線程堆棧和堆箩艺。 在硬件上窜醉,線程堆棧和堆都位于主內(nèi)存中。 線程堆棧和堆的一部分有時(shí)可能存在于CPU高速緩存和內(nèi)部CPU寄存器中艺谆。 這在圖中說明:

image

當(dāng)對(duì)象和變量可以存儲(chǔ)在計(jì)算機(jī)的各種不同的存儲(chǔ)區(qū)域中時(shí)榨惰,可能會(huì)出現(xiàn)某些問題。 兩個(gè)主要問題是:

  • 線程更新(寫入)到共享變量的可見性静汤。
  • 讀取琅催,檢查和寫入共享變量時(shí)的競(jìng)爭(zhēng)條件

這兩個(gè)問題將在以下部分中解釋。

共享對(duì)象的可見性

如果兩個(gè)或多個(gè)線程共享一個(gè)對(duì)象虫给,沒有正確使用volatile聲明或同步藤抡,一個(gè)線程所做的共享對(duì)象的更新可能對(duì)其他線程是不可見的。

假設(shè)共享對(duì)象最初存儲(chǔ)在主內(nèi)存中抹估。 在CPU 1上運(yùn)行的線程然后將共享對(duì)象讀入其CPU緩存杰捂。 在那里它對(duì)共享對(duì)象進(jìn)行了更改。 只要CPU緩存尚未刷新到主內(nèi)存棋蚌,共享對(duì)象的更改版本對(duì)于在其他CPU上運(yùn)行的線程不可見嫁佳。 這樣一來,每個(gè)線程可能會(huì)以自己的共享對(duì)象副本結(jié)束谷暮,每個(gè)副本都坐在不同的CPU緩存中蒿往。

下圖說明了草圖的情況。 在左CPU上運(yùn)行的一個(gè)線程將共享對(duì)象復(fù)制到其CPU緩存中湿弦,并將其計(jì)數(shù)變量更改為2.對(duì)于正確CPU上運(yùn)行的其他線程瓤漏,此更改不可見,因?yàn)楦掠?jì)數(shù)尚未刷新到主 記憶還沒

image

要解決這個(gè)問題,你可以使用Java的volatile關(guān)鍵字蔬充。 volatile關(guān)鍵字可以確保給定的變量直接從主內(nèi)存中讀取蝶俱,并在更新時(shí)總是寫回主內(nèi)存。

注意
volatile并不能保證線程的安全饥漫,只是在某種場(chǎng)景下使用才能保證線程安全榨呆。如果有且只有一個(gè)線程在寫,其他的所有線程都在讀庸队,那么可以保證線程的安全积蜻,如果多個(gè)線程寫多個(gè)線程讀,那么不能保證線程安全

條件競(jìng)爭(zhēng)

如果兩個(gè)或多個(gè)線程共享對(duì)象彻消,并且多個(gè)線程更新該共享對(duì)象中的變量竿拆,則可能會(huì)發(fā)生競(jìng)爭(zhēng)條件。

假設(shè)線程A將共享對(duì)象的變量計(jì)數(shù)讀入其CPU緩存中宾尚。 想像一下丙笋,那個(gè)線程B也是一樣的,但進(jìn)入不同的CPU緩存煌贴。 現(xiàn)在線程A增加一個(gè)計(jì)數(shù)不见,線程B也是一樣的。 現(xiàn)在崔步,var1已經(jīng)增加了兩次稳吮,每次CPU緩存一次。

如果這些增量依次執(zhí)行井濒,則變量計(jì)數(shù)將被增加兩次灶似,并將原始值+ 2寫回到主存儲(chǔ)器。

但是瑞你,兩個(gè)增量在沒有正確同步的情況下同時(shí)進(jìn)行酪惭。 不管線程A和B哪個(gè)將其更新版本的計(jì)數(shù)寫回主內(nèi)存,盡管有兩個(gè)增量者甲,更新后的值將僅比原始值高1春感。

該圖說明了如上所述的競(jìng)爭(zhēng)條件的問題的發(fā)生:

image

要解決此問題,您可以使用Java同步塊虏缸。 同步塊保證在任何給定時(shí)間只有一個(gè)線程可以進(jìn)入代碼的給定關(guān)鍵部分鲫懒。 同步塊還保證在同步塊內(nèi)訪問的所有變量將從主存儲(chǔ)器讀入,并且當(dāng)線程退出同步塊時(shí)刽辙,所有更新的變量將被刷新回主存儲(chǔ)器窥岩,而不管該變量是否被聲明為volatile。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末宰缤,一起剝皮案震驚了整個(gè)濱河市颂翼,隨后出現(xiàn)的幾起案子晃洒,更是在濱河造成了極大的恐慌,老刑警劉巖朦乏,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件球及,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡呻疹,警方通過查閱死者的電腦和手機(jī)吃引,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來诲宇,“玉大人际歼,你說我怎么就攤上這事惶翻」美叮” “怎么了?”我有些...
    開封第一講書人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵吕粗,是天一觀的道長(zhǎng)纺荧。 經(jīng)常有香客問我,道長(zhǎng)颅筋,這世上最難降的妖魔是什么宙暇? 我笑而不...
    開封第一講書人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮议泵,結(jié)果婚禮上占贫,老公的妹妹穿的比我還像新娘。我一直安慰自己先口,他們只是感情好型奥,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著碉京,像睡著了一般厢汹。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上谐宙,一...
    開封第一講書人閱讀 51,692評(píng)論 1 305
  • 那天烫葬,我揣著相機(jī)與錄音,去河邊找鬼凡蜻。 笑死搭综,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的划栓。 我是一名探鬼主播设凹,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼茅姜!你這毒婦竟也來了闪朱?” 一聲冷哼從身側(cè)響起月匣,我...
    開封第一講書人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎奋姿,沒想到半個(gè)月后锄开,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡称诗,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年萍悴,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片寓免。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡癣诱,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出袜香,到底是詐尸還是另有隱情撕予,我是刑警寧澤,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布蜈首,位于F島的核電站实抡,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏欢策。R本人自食惡果不足惜吆寨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望踩寇。 院中可真熱鬧啄清,春花似錦、人聲如沸俺孙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鼠冕。三九已至添寺,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間懈费,已是汗流浹背计露。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留憎乙,地道東北人票罐。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像泞边,于是被迫代替她去往敵國(guó)和親该押。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 從三月份找實(shí)習(xí)到現(xiàn)在阵谚,面了一些公司蚕礼,掛了不少烟具,但最終還是拿到小米、百度奠蹬、阿里朝聋、京東、新浪囤躁、CVTE冀痕、樂視家的研發(fā)崗...
    時(shí)芥藍(lán)閱讀 42,253評(píng)論 11 349
  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結(jié)構(gòu)(3).初始化時(shí)...
    歐辰_OSR閱讀 29,392評(píng)論 8 265
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,103評(píng)論 1 32
  • “一直都不是那么幸運(yùn)的人 投胎技術(shù)不過硬 兌獎(jiǎng)卷永遠(yuǎn)只能刮出謝謝 喜歡的人總是看不見你 也不知道努力多久才能變成自...
    那年臘月初六閱讀 218評(píng)論 0 0
  • 第一幅真正意義上的自我介紹導(dǎo)圖作品 老師講評(píng)加自評(píng)后,用鉛筆圈注了以后注意點(diǎn):關(guān)鍵圖再大些狸演,主題再大些言蛇。 思維導(dǎo)圖...
    自由最美閱讀 231評(píng)論 0 0