偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

從零開始掌握 JVM

開發(fā)
無(wú)論你是剛剛接觸 Java 編程的新手,還是希望深入了解 JVM 內(nèi)部運(yùn)作的技術(shù)愛好者,這篇文章都將為你提供全面而易懂的知識(shí)點(diǎn)介紹。

在當(dāng)今的軟件開發(fā)領(lǐng)域,Java 語(yǔ)言及其運(yùn)行環(huán)境——Java 虛擬機(jī)(JVM)占據(jù)了舉足輕重的地位。無(wú)論是企業(yè)級(jí)應(yīng)用、Web 應(yīng)用還是移動(dòng)應(yīng)用,JVM 都扮演著核心角色。然而,對(duì)于許多初學(xué)者來(lái)說,理解 JVM 的工作原理和內(nèi)部機(jī)制可能是一項(xiàng)挑戰(zhàn)。

本文將帶你從零開始,逐步了解 JVM 的基本概念、結(jié)構(gòu)與功能。無(wú)論你是剛剛接觸 Java 編程的新手,還是希望深入了解 JVM 內(nèi)部運(yùn)作的技術(shù)愛好者,這篇文章都將為你提供全面而易懂的知識(shí)點(diǎn)介紹。

一、詳解JVM基礎(chǔ)概念

1.什么是JVM?JVM的作用是什么

JVM是Java設(shè)計(jì)者用于屏蔽多平臺(tái)差異,基于操作系統(tǒng)之上的一個(gè)"小型虛擬機(jī)",正是因?yàn)镴VM的存在,使得Java應(yīng)用程序運(yùn)行時(shí)不需要關(guān)注底層操作系統(tǒng)的差異。使得Java程序編譯只需編譯一次生成class字節(jié)碼,即可在任何操作系統(tǒng)都可以以相同的方式運(yùn)行。

2.JVM運(yùn)行時(shí)區(qū)域劃分

(1) JVM體系結(jié)概覽

因?yàn)镴VM屏蔽了底層操作系統(tǒng)的差異,所以它自成了一套內(nèi)存結(jié)構(gòu)進(jìn)行獨(dú)立的內(nèi)存管理,整體來(lái)說JVM可分為以下幾個(gè)部分:

  • 方法區(qū)
  • 堆區(qū)
  • 虛擬機(jī)棧和本地方法棧
  • 程序計(jì)數(shù)器

對(duì)應(yīng)的我們也給出一張宏觀的圖片:

(2) 方法區(qū)

我們先來(lái)說說方法區(qū),這里我們所說的方法區(qū)指的不是存放Java方法的區(qū)域,并且它也只是一個(gè)邏輯上的物理區(qū)域的概念,在不同的JDK版本中它的實(shí)現(xiàn)都會(huì)有所和不同,方法區(qū)主要存放的數(shù)據(jù)包括:

  • 類信息:例如類名、父類名、接口列表、常量池、字段表、方法表等。
  • 常量池:存儲(chǔ)編譯器生產(chǎn)的各種字面量和符號(hào)引用。
  • 方法代碼:包括方法的字節(jié)碼指令和其他輔助信息,例如操作數(shù)棧和局部變量表等。
  • 靜態(tài)變量:屬于類的各種靜態(tài)變量。
  • 類的構(gòu)造器和初始化塊。

(3) 堆內(nèi)存

然后就是JVM的堆區(qū),對(duì)象實(shí)例和數(shù)組大部分都會(huì)存儲(chǔ)在這塊內(nèi)存空間中,注意筆者這里所說的一個(gè)強(qiáng)調(diào)——大部分,因?yàn)楝F(xiàn)代即時(shí)編譯技術(shù)的進(jìn)步,在JVM進(jìn)行逃逸分析時(shí)如果發(fā)現(xiàn)對(duì)象并未逃逸,則會(huì)直接進(jìn)行棧上分配、標(biāo)量替換等手段將其分配在??臻g,并且java堆區(qū)是線程共享區(qū)域的,所以多線程情況下操作相同對(duì)象可能存在線程安全問題。

(4) 虛擬機(jī)棧

我們?nèi)粘?duì)象實(shí)例的方法調(diào)用都是在虛擬機(jī)棧上運(yùn)行的,它是Java方法執(zhí)行的內(nèi)存模型,存儲(chǔ)著被執(zhí)行方法的局部變量表、動(dòng)態(tài)鏈表、方法入口、棧的操作用(入棧和出棧)。

由于虛擬機(jī)棧是棧結(jié)構(gòu)所以方法調(diào)用按順序壓入棧中,就會(huì)倒序彈出虛擬機(jī)棧,例如我們的下面這段代碼:

public void a(){
b();
}
public void b(){
c();
}

public void c(){
}

當(dāng)線程調(diào)用a方法時(shí),優(yōu)先為a產(chǎn)生一個(gè)棧幀A壓入棧中,發(fā)現(xiàn)a方法調(diào)用了b方法,再為b產(chǎn)生一個(gè)棧幀B壓入棧中,然后b再調(diào)用c方法,再為c產(chǎn)生一個(gè)棧幀C方法壓入棧中。

同理,執(zhí)行順序也是c先執(zhí)行結(jié)束,優(yōu)先彈出棧,然后是b,最后是a。由此我們可知Java中方法是可以嵌套調(diào)用的,但這并不意味方法可以無(wú)線層次的嵌套調(diào)用,當(dāng)方法嵌套調(diào)用深度超過了虛擬機(jī)棧規(guī)定的最大深度,就會(huì)拋出StackOverflowError,而這個(gè)錯(cuò)誤也常常發(fā)生在我們編寫的無(wú)終止條件的遞歸代碼中。

虛擬機(jī)棧屬于線程獨(dú)享,所以也就沒有什么生命周期的概念,每個(gè)方法隨著調(diào)用的結(jié)束??臻g也隨之釋放,所以棧的生命周期也可以理解為和線程生命周期是一致的。

每個(gè)方法的調(diào)用都是往虛擬機(jī)棧中壓入一個(gè)棧幀,例如上述我們調(diào)用a方法,就是將a方法壓入棧幀,而每一個(gè)棧幀都有一個(gè)局部變量表,這個(gè)局部變量表用于記錄方法體內(nèi)的某些基本類型(byte、short、int、boolean、float、char、long、double)還有對(duì)象引用(不等同于對(duì)象本省,可能是一個(gè)指向?qū)ο笃鹗嫉刂返囊弥羔?和returnAddress(指向一條字節(jié)碼指令的地址)。

這些數(shù)據(jù)都會(huì)存儲(chǔ)在局部變量表的slot槽中,在某些情況下每個(gè)棧幀可能存在復(fù)用,我們不妨舉個(gè)例子,可以看到下面這段代碼就是在main方法上分配一個(gè)byte數(shù)組,我們添加一個(gè)-verbose:gc參數(shù)觀察gc回收情況:

public static void main(String[] args) {   
    byte[] placeHolder = new byte[1024 * 1024 * 64];
    System.gc();
 }

查看輸出結(jié)果可以看到byte數(shù)組空間沒有被回收,就是因?yàn)閟lot局部變量placeHolder 對(duì)應(yīng)的槽還沒有被其他變量所復(fù)用,這也就意味著此刻可達(dá)性算法分析認(rèn)為這塊placeHolder 不可被GC所以就不會(huì)被垃圾回收:

[GC (System.gc())  86054K->68541K(243712K), 0.0023357 secs]
[Full GC (System.gc())  68541K->68243K(243712K), 0.0203291 secs]

對(duì)此我們簡(jiǎn)單調(diào)整一下代碼,將placeHolder 放在某個(gè)作用域里,只要執(zhí)行走出這個(gè)作用域,就意味著placeHolder 為無(wú)用的局部變量,后續(xù)新分配的a就會(huì)直接復(fù)用局部變量表的空間:

public static void main(String[] args) {
        {
            //placeHolder在代碼塊的作用域內(nèi)完成內(nèi)存分配
            byte[] placeHolder = new byte[1024 * 1024 * 64];
        }
        //分配一個(gè)新的變量嘗試復(fù)用上述slot
        int a = 0;
        System.gc();
    }

這也就是為什么本次gc可以回收64M的內(nèi)存空間的原因:

[GC (System.gc())  86054K->68502K(243712K), 0.0023594 secs]
[Full GC (System.gc())  68502K->2707K(243712K), 0.0221691 secs]

小結(jié)一下虛擬棧的特點(diǎn):

  • 是方法執(zhí)行時(shí)的內(nèi)存模型。
  • 方法調(diào)用以棧幀形式壓入棧中。
  • 方法嵌套調(diào)用并將棧幀壓入棧幀時(shí),深度操作虛擬機(jī)棧最大深度會(huì)報(bào)StackOverflowError。
  • 虛擬機(jī)棧的局部變量表隨著變量使用的完結(jié),之前的內(nèi)存區(qū)域可被復(fù)用。
  • 棧的生命周期跟隨線程,線程調(diào)用結(jié)束棧即可被銷毀。

本地方法棧

下面這個(gè)帶有native關(guān)鍵字的方法就是在本地方法,它就是本地方法棧管理的方法,其工作機(jī)制和特點(diǎn)是虛擬機(jī)棧是差不多的,所以這里就不多做介紹了。

private native void start0();

(5) 程序計(jì)數(shù)器

程序計(jì)數(shù)器和我們操作系統(tǒng)學(xué)習(xí)的程序計(jì)數(shù)器概念差不多,是一塊比較小的內(nèi)存空間,我們可以將其看作當(dāng)前現(xiàn)場(chǎng)所執(zhí)行的字節(jié)碼行號(hào)的指示器,記錄著當(dāng)前線程下一條要執(zhí)行的指令的地址,對(duì)于程序中的分支、循環(huán)、跳轉(zhuǎn)、異常以及線程恢復(fù)和掛起都是基于這個(gè)計(jì)數(shù)器完成的。

我們以下面這段代碼為例展示一下程序計(jì)數(shù)器實(shí)質(zhì)記錄的信息:

public static void main(String[] args) {

        int num = 1;
        int num2 = 2;
        int num3 = 3;
        System.out.println("total: " + (num + num2 + num3));
    }

可以看到實(shí)際上其編譯后的字節(jié)碼內(nèi)容如上,每一行指令前方所記錄的字節(jié)碼的偏移地址就是程序計(jì)數(shù)器所記錄的地址信息:

因?yàn)槭敲恳粋€(gè)線程都有各自的計(jì)數(shù)器,所以我們可以認(rèn)為計(jì)數(shù)器是不會(huì)互相影響是線程安全的。需要注意的是程序計(jì)數(shù)器只有在記錄虛擬機(jī)棧的方法時(shí)才會(huì)有值,對(duì)于native方法,程序計(jì)數(shù)器是不工作的。

二、詳解JVM類加載器

1.什么是類加載器

類加載器實(shí)現(xiàn)將編譯后的class文件加載到內(nèi)存,并轉(zhuǎn)為為運(yùn)行時(shí)區(qū)域劃分的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu),注意類加載器只能決定類的加載,至于能不能運(yùn)行則是由Execution Engine 來(lái)決定。

整體來(lái)說,類加載器對(duì)應(yīng)類的生命周期應(yīng)該是以下幾個(gè)階段:

  • 加載
  • 鏈接:分為驗(yàn)證、準(zhǔn)備、解析
  • 初始化
  • 使用:此時(shí)用戶就可以基于這個(gè)類創(chuàng)建實(shí)例了
  • 卸載

2.類的加載

加載的過程本質(zhì)上就是將class文件加載到JVM中,JVM根據(jù)類的全限定名獲取定義該類的二進(jìn)制字節(jié)流。

  • 將編譯后class文件加載到內(nèi)存。
  • 將靜態(tài)數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)換成方法區(qū)中運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)。
  • 在堆區(qū)創(chuàng)建一個(gè)java.lang.Class對(duì)象作為數(shù)據(jù)訪問的入口。

3.鏈接的過程

鏈接整體是分為上述所說的3個(gè)過程:

  • 驗(yàn)證:分為驗(yàn)證階段主要是校驗(yàn)類的文件格式、元數(shù)據(jù)、字節(jié)碼、二進(jìn)制兼容性
  • 準(zhǔn)備:在方法區(qū)為靜態(tài)變量常見空間,并對(duì)其進(jìn)行初始化,例如private static int a=3;,在此階段就會(huì)在方法區(qū)完成創(chuàng)建,并初始默認(rèn)值0。
  • 解析:即將類的符號(hào)引用直接轉(zhuǎn)換為直接引用,引用包括但不限于類、接口、字段、類方法、接口方法、方法類型、方法句柄、發(fā)文控制修飾符等,例如import java.util.ArrayList在此階段就會(huì)直接轉(zhuǎn)為指針或者對(duì)象地址。

4.初始化

將方法區(qū)中準(zhǔn)備好的值,通過調(diào)用<cinit>完成初始化工作。<cinit>會(huì)收集好所有的賦值動(dòng)作,例如上文的private static int a=3就是這時(shí)候完成賦值的。

5.卸載

當(dāng)對(duì)象使用完成后,GC將無(wú)用對(duì)象從內(nèi)存中卸載。

6.類加載器的加載順序

其實(shí)類加載器并非只有一個(gè),按照分類我們可以將其分為:

BootStrap ClassLoader:rt.jar
Extention ClassLoader: 加載擴(kuò)展的jar包
App ClassLoader:指定的classpath下面的jar包
Custom ClassLoader:自定義的類加載器

所以,為了保證JDK自帶rt.jar的類能夠正常加載,就出現(xiàn)了一種名為雙親委派的類加載機(jī)制。

舉個(gè)例子,JDK自帶的包中有一個(gè)名為String的類,而我們自定義的代碼中也有一個(gè)String類,我們自己的類肯定是由App ClassLoader完成加載,如果我們的類加載器優(yōu)先執(zhí)行,那么JDK自帶的String類就無(wú)法被使用到。

所以雙親委派機(jī)制就規(guī)定了類加載優(yōu)先由BootStrap ClassLoader先加載,只有根加載器加載不到需要的類,才會(huì)交由下層類完成加載。 正是因?yàn)殡p親委派機(jī)制的存在,jdk自帶的String類才能夠正常的使用,而我們也無(wú)法通過自定義String類進(jìn)行重寫。

類加載器的工作流程為:

  • 加載class文件到方法區(qū)并轉(zhuǎn)為運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu),并在堆區(qū)創(chuàng)建一個(gè)Class對(duì)象作為入口
  • 驗(yàn)證class的類方法是否由危害JVM的行為
  • 準(zhǔn)備階段初始化靜態(tài)變量數(shù)據(jù)
  • 解析階段將符號(hào)引用轉(zhuǎn)為可以可直接導(dǎo)向?qū)ο蟮刂返闹苯右?/li>
  • 初始化階段通過cinit方法初始化對(duì)象實(shí)例變量等數(shù)據(jù)
  • 使用完成后該類就會(huì)被卸載。

7.用一個(gè)線程的代碼執(zhí)行解釋Java文件是如何被運(yùn)行的

如下所示,我們編寫一個(gè)Student 類,他有name這個(gè)成員屬性:

/**
 * 學(xué)生類
 */
public class Student {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

然后我們編寫一個(gè)main方法,調(diào)用student類,完成屬性賦值。

public class Main {

    public static void main(String[] args) throws InterruptedException {
        Student student = new Student();
        student.setName("小明");
    }

   }

首先編譯得到Main.class文件后,系統(tǒng)會(huì)啟動(dòng)一個(gè)JVM進(jìn)程,從classpath中找到這個(gè)class的二進(jìn)制文件,將在到方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)區(qū)域:

再將當(dāng)前執(zhí)行的main方法壓入虛擬機(jī)棧中:

main方法中需要new Student();,JVM發(fā)現(xiàn)方法區(qū)中沒有Student類的信息,于是開始加載這個(gè)類,將這個(gè)類的信息存放到方法區(qū),并在堆區(qū)創(chuàng)建一個(gè)Class對(duì)象作為方法區(qū)信息的入口。

new Student();在此時(shí)就會(huì)根據(jù)類元信息獲取創(chuàng)建student對(duì)象所需要的空間大小,在堆區(qū)申請(qǐng)并開辟一個(gè)空間調(diào)用構(gòu)造函數(shù)創(chuàng)建Student實(shí)例。

main方法調(diào)用setName,student 的引用找到堆區(qū)的Student,通過其引用找到方法區(qū)中Student 類的方法表得到方法的字節(jié)碼地址,從而完成調(diào)用。

上述步驟完成后,方法按照入棧順序后進(jìn)先出的彈出,虛擬機(jī)棧隨著線程一起銷毀。

三、詳解虛擬機(jī)堆

1.區(qū)域劃分

JVM將堆內(nèi)存分為年輕代和老年代。以及一個(gè)非堆內(nèi)存區(qū)域,我們稱為永久代,注意:這里所說的永久代只有在JDK8之前才會(huì)出現(xiàn),對(duì)此我們也給出JDK8之前版本的堆內(nèi)存區(qū)域劃分圖解:

在Java8之后考慮到與其他規(guī)范的虛擬機(jī)的兼容性以及GC效率,將方法區(qū)的實(shí)現(xiàn)交由元空間實(shí)現(xiàn),元空間所使用的內(nèi)存都是本地內(nèi)存,這里的本地內(nèi)存說的就是我們物理機(jī)上的內(nèi)存,所以理論上物理機(jī)內(nèi)存多大,元空間內(nèi)存就可以分配多大,元空間大小分配和JVM從物理機(jī)上分配的內(nèi)存大小沒有任何關(guān)系。

對(duì)應(yīng)的我們也給出元空間兩個(gè)設(shè)置參數(shù):

  • MetaspaceSize:初始化元空間大小,控制發(fā)生GC
  • MaxMetaspaceSize:限制元空間大小上限,防止占用過多物理內(nèi)存。

2.詳解新生代

我們?cè)賮?lái)聊聊年輕代,新生代又可以分為Eden和Survivor區(qū),Survivor區(qū)又被平均分為兩塊。所以年代整體比例為8:1:1。當(dāng)然這個(gè)值也可以通過-XX:+UsePSAdaptiveSurvivorSizePolicy來(lái)調(diào)整。

任何對(duì)象剛剛創(chuàng)建的時(shí)候都會(huì)放在Eden區(qū)。我們都知道堆區(qū)內(nèi)存是共享的,所以Eden區(qū)的空間也是多線程共享的,但是為了確保多線程彼此之間相對(duì)獨(dú)立(注意是線程之間彼此獨(dú)立而不是操作Eden區(qū)對(duì)象獨(dú)立),Eden區(qū)會(huì)專門劃出一塊連續(xù)的空間給每個(gè)線程分配一個(gè)獨(dú)立空間,這個(gè)空間叫做TLAB空間,每個(gè)線程都可以操作自己的TLAB空間和讀取其他線程的TLAB空間。

一旦Eden區(qū)滿了之后,就會(huì)觸發(fā)第一次Minor GC,就會(huì)將存活的對(duì)象從Eden區(qū)放到Survivor區(qū)。

需要注意的是,Survivor分為Survivor0和Survivor1區(qū)。JVM使用from和to兩個(gè)指針管理這兩塊區(qū)域,其中from指針指向有對(duì)象的區(qū)域空間,to指針指向空閑區(qū)域的Survivor空間。

從Eden區(qū)中存活下來(lái)首先會(huì)在Survivor0區(qū),一旦下一次Eden區(qū)空間滿了之后就再次觸發(fā)Minor GC 將Eden區(qū)和Survivor0區(qū)存活的對(duì)象復(fù)制到Survivor1區(qū),就這樣保存存活的對(duì)象在兩個(gè)Survivor區(qū)中來(lái)回游走,直到晉升到老年代:

經(jīng)過15次之后還活著的對(duì)象就會(huì)被存放到老年代,這里是15是由-XX:MaxTenuringThreshold指定的,-XX:MaxTenuringThreshold 占4位,默認(rèn)配置為15。 這里補(bǔ)充一下,同樣會(huì)將Survivor存放到老年代的第2個(gè)條件,當(dāng)Survivor區(qū)對(duì)象比例達(dá)到XX:TargetSurvivorRatio時(shí),也會(huì)將存活的對(duì)象放到老年區(qū)。

3.詳解老年代

老年代存放的都是經(jīng)歷過無(wú)數(shù)次GC的老對(duì)象,一旦這個(gè)空間滿了之后就會(huì)出現(xiàn)一次Full GC,F(xiàn)ull GC期間所有線程都會(huì)停止手頭工作等待Full GC完成,所以在此期間,系統(tǒng)可能會(huì)出現(xiàn)卡頓現(xiàn)象。 這就意味著在高并發(fā)多對(duì)象創(chuàng)建場(chǎng)景的情況下,我們需要合理分配老年區(qū)的內(nèi)存。一旦Full GC后還是無(wú)法容納新對(duì)象,就會(huì)報(bào)OOM問題。

四、JVM如何判斷對(duì)象是否需要被銷毀

1.引用計(jì)數(shù)器法

一個(gè)對(duì)象被引用時(shí)+1,被解除引用時(shí)-1。我們根據(jù)引用計(jì)數(shù)結(jié)果決定是否GC,但是這種方式無(wú)法解決兩個(gè)對(duì)象互相引用的情況。例如我們棧區(qū)沒有一個(gè)引用指向當(dāng)前兩個(gè)對(duì)象,可堆區(qū)兩個(gè)對(duì)象卻互相引用對(duì)方。

2.可達(dá)性分析法

將一系列的GC ROOTS作為起始的存活對(duì)象集,查看是否有任意一個(gè)GC ROOTS可以到達(dá)這個(gè)對(duì)象,都不可達(dá)就說明這個(gè)對(duì)象要被回收了。

而以下幾種可以作為GC ROOTS:

  • 虛擬機(jī)棧中的局部變量等,被該變量引用的對(duì)象不可回收。
  • 方法區(qū)的靜態(tài)變量,被該變量引用的對(duì)象不可回收。
  • 方法區(qū)的常量,被該變量引用的對(duì)象不可回收。
  • 本地方法棧(即native修飾的方法),被該變量引用的對(duì)象不可回收。
  • 未停止且正在使用該對(duì)象的線程,被該線程引用的對(duì)象不可回收。

通過可達(dá)性算法分析對(duì)象是否被回收需要經(jīng)過兩個(gè)階段:

  • 可達(dá)性分析法發(fā)現(xiàn)不可達(dá)的對(duì)象后,就將其第一次標(biāo)記一下,然后判斷該對(duì)象的是否要執(zhí)行finalize()方法,若確定則將其存到F-Queue中。
  • 將F-Queue中的對(duì)象調(diào)用finalize(),若此時(shí)還是沒有任何引用鏈引用,則說明這個(gè)對(duì)象要被回收了。

五、詳解幾種常見垃圾回收算法

1.標(biāo)記清除法

如下圖,這種算法很簡(jiǎn)單,標(biāo)記出需要被回收的對(duì)象的空間,然后直接清除。同樣的缺點(diǎn)也很明顯,容易造成內(nèi)存碎片,內(nèi)存碎片也很好理解,回收的對(duì)象空間都是一小塊一小塊的,當(dāng)我們需要?jiǎng)?chuàng)建一個(gè)大對(duì)象時(shí)就沒有一塊連續(xù)大空間供其使用。

2.復(fù)制算法

這種算法和上文說的survivor一樣,將空間一分為二,from存放當(dāng)前活著的對(duì)象,to作為空閑空間。在進(jìn)行回收時(shí),將沒有被標(biāo)記回收的對(duì)象挪到另一個(gè)空間,然后from指向另一個(gè)空間。這種算法缺點(diǎn)也很明顯,可利用空間就一半。

3.標(biāo)記整理

這種算法算是復(fù)制算法的改良版,將存活對(duì)象全部挪動(dòng)到一段,確??臻e和對(duì)象空間都是連續(xù)的,且空間利用率100%。

4.分代收集算法(綜合算法)

這種算法就是上面算法的組合,即年輕代存活率低,采用復(fù)制算法。老年代存活率高,采用標(biāo)記清除算法或者標(biāo)記整理算法。例如hotspot虛擬機(jī)的搭配就是新生代采用復(fù)制算法,每次觸發(fā)Minor gc就將Eden和survivor區(qū)存活的對(duì)象移動(dòng)到to指針指向的survivor區(qū),而老年代而用標(biāo)記整理法將存活的對(duì)象都?xì)w整到同一個(gè)段中:


責(zé)任編輯:趙寧寧 來(lái)源: 寫代碼的SharkChili
相關(guān)推薦

2024-11-27 16:25:54

JVMJIT編譯機(jī)制

2023-11-16 08:53:05

NumPy庫(kù)Python

2020-07-02 15:32:23

Kubernetes容器架構(gòu)

2015-11-17 16:11:07

Code Review

2019-01-18 12:39:45

云計(jì)算PaaS公有云

2018-04-18 07:01:59

Docker容器虛擬機(jī)

2017-03-14 14:04:24

Python機(jī)器學(xué)習(xí)

2024-05-15 14:29:45

2010-05-26 17:35:08

配置Xcode SVN

2018-09-14 17:16:22

云計(jì)算軟件計(jì)算機(jī)網(wǎng)絡(luò)

2024-04-10 07:48:41

搜索引擎場(chǎng)景

2011-04-06 15:55:50

開發(fā)webOS程序webOS

2015-10-15 14:16:24

2024-11-28 10:35:47

2024-12-13 16:03:59

2023-11-21 08:57:16

2011-09-05 14:17:54

Sencha ToucMVC

2024-07-31 08:14:17

2020-02-11 16:49:24

React前端代碼

2014-07-22 13:09:21

android
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)