自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

面試官問我平時(shí)寫的Bug的存儲位置

存儲 存儲軟件
說到寫bug,我們每天都在用Java實(shí)現(xiàn)著各種需求,我們實(shí)現(xiàn)的Java程序每天都運(yùn)行在每個(gè)機(jī)器的虛擬機(jī)上,但是你了解你寫的代碼的具體存儲位置嗎?

[[386829]]

本文轉(zhuǎn)載自微信公眾號「大魚仙人」,作者大魚 。轉(zhuǎn)載本文請聯(lián)系大魚仙人公眾號。

說到寫bug,我們每天都在用Java實(shí)現(xiàn)著各種需求,我們實(shí)現(xiàn)的Java程序每天都運(yùn)行在每個(gè)機(jī)器的虛擬機(jī)上,但是你了解你寫的代碼的具體存儲位置嗎

說實(shí)話,這個(gè)東西,在我剛開始學(xué)Java的時(shí)候,我聽到JVM虛擬機(jī)這個(gè)名詞的時(shí)候,我的感覺是這個(gè)樣子的(慚愧

你們肯定也會有些疑問吧,平時(shí)寫的代碼每一部分都是存儲在哪里的?是的,沒錯,我的內(nèi)心就像拖著下巴的那位,除了,模樣,emmm...

雖然現(xiàn)在也不是多么的精通,但是比之前好太多了,不是涉及很底層的東西也算是了解一些,當(dāng)然真要是問我各種涉及細(xì)節(jié),毫不謙虛的說,以我的水平,我可能只會阿巴阿巴(逃

如果大家對更深入的JVM感興趣,可以和JVM大神R大這種多去溝通溝通

是的,沒錯,其實(shí)我這個(gè)文章算是掃盲文章,但是在掃盲文章的基礎(chǔ)上說的更細(xì)一點(diǎn),更多一點(diǎn),我也會給大家拋出一些面試官愛問的問題,并且?guī)痛蠹医獯穑源蠹艺埍M情讀下去,肯定會讓你有所收獲

大家覺得不錯的點(diǎn)個(gè)關(guān)注,大家一起探討、一起學(xué)習(xí)、一起進(jìn)步

JVM內(nèi)存結(jié)構(gòu)

JVM內(nèi)存布局,先給大家上個(gè)圖

如果你是讀過JVM文章的養(yǎng)魚仔的話,那你肯定看過上面類似的圖,我在給大家放一張,大家在熟悉一遍,看過的回一下,沒看過的混個(gè)臉熟

JVM內(nèi)存主要分為堆、虛擬機(jī)棧、本地方法棧、方法區(qū)、程序計(jì)數(shù)器等,堆是虛擬機(jī)內(nèi)存占據(jù)最大的一部分,堆的目的就是盛放大量的對象實(shí)例的;虛擬機(jī)棧對應(yīng)的是方法的執(zhí)行過程,本地方法棧是用來調(diào)用本地方法的執(zhí)行過程;方法區(qū)就是用來存儲存儲類信息、常量、靜態(tài)變量的數(shù)據(jù),是線程共享的數(shù)據(jù);程序計(jì)數(shù)器,就是存儲著線程下一條將要執(zhí)行的指令

每個(gè)區(qū)域都有其特定的功能,就像是一個(gè)企業(yè),一個(gè)工作室,每個(gè)人發(fā)揮著自己的長處,各司其職

走著吧,各位養(yǎng)魚仔(我是魚),一起來瞧瞧每一部分的具體的細(xì)節(jié)以及面試官愛問的問題

虛擬機(jī)堆

Java堆是垃圾收集器管理的主要地方,因此很多的時(shí)候也被稱為GC堆,Java堆還可以分為年輕代和老年代,年輕代又可以分為Eden空間、From Survivor空間、To Survivor空間,默認(rèn)是8:1:1的比例

根據(jù)Java虛擬機(jī)規(guī)范的規(guī)定,Java堆可以處于物理上不連續(xù)的內(nèi)存空間中,只要邏輯上是連續(xù)的即可,就像我們的磁盤空間一樣

在實(shí)現(xiàn)時(shí),既可以實(shí)現(xiàn)成固定大小的,也可以是可擴(kuò)展的,不過當(dāng)前主流的虛擬機(jī)都是按照可擴(kuò)展來實(shí)現(xiàn)的(通過-Xmx和-Xms控制);如果在堆中沒有內(nèi)存完成實(shí)例分配,并且堆也無法再擴(kuò)展時(shí),將會拋出OutOfMemoryError異常。

打斷一下,Java堆的區(qū)域都是線程共享的嗎?

當(dāng)你聽到這個(gè)問題的時(shí)候,你首先想到的是什么呢?

let me tell you,面試官其實(shí)問這個(gè)的時(shí)候就是在看你對堆的了解程度,你只知道是用來放對象實(shí)例的,那面試官對你表現(xiàn)覺得不算非常滿意;但是如果你知道TLAB,并且知道它的原理和問題,那面試官就會覺得:這小伙子不一般,我得再多深入了解了解,可以考慮當(dāng)我的好助手

首先,你得肯定回答,沒錯,堆是全局共享的,但是會存在一些問題,那就是多個(gè)線程在堆上同時(shí)申請空間,如果在并發(fā)的場景中,兩個(gè)線程先后把對象引用指向了同一個(gè)內(nèi)存區(qū)域,那可能就會出現(xiàn)問題;為了解決這個(gè)問題呢,就得進(jìn)行同步控制,說到同步控制,就會影響到效率

就拿Hotspot來舉例子,它的解決方案是每個(gè)線程在堆中都預(yù)先分配一小塊內(nèi)存,然后再給對象分配內(nèi)存的時(shí)候,先在這塊“私有內(nèi)存”進(jìn)行分配,這塊用完之后再去分配新的“私有內(nèi)存”,這就是TLAB分配

你也看到了,我加引號了,它并不是真正意義上的私有,而是表面上的私有;它是從堆內(nèi)存劃分出來的,有了TLAB技術(shù),堆內(nèi)存并不是完完全全的線程共享,每個(gè)線程在初始化的時(shí)候都會去內(nèi)存中申請一塊TLAB

切記:并不是TLAB區(qū)域的內(nèi)存其它線程完全無法訪問,其它線程也是可以讀取的,只不過無法在這個(gè)區(qū)域分配內(nèi)存而已

說到這的時(shí)候,也給面試官一個(gè)眼神,說明我的干貨還沒完,我還能繼續(xù)吹

難道TLAB很完美嗎?所謂,金無足赤人無完人,肯定有他的問題所在

我們知道TLAB是線程特有的,它的內(nèi)存區(qū)域不是很大,所以會出現(xiàn)一些不夠用的情況,比如一個(gè)線程的TLAB的空間有100KB,其中已經(jīng)使用了80KB,如果還需要再分配一個(gè)30KB的對象,則無法直接在TLAB上分配了,這種情況有兩種解決辦法

  • 直接在堆中分配
  • 廢棄當(dāng)前TLAB,重新申請TLAB空間再次進(jìn)行內(nèi)存分配

其實(shí)兩種各有利弊,第一種的缺點(diǎn)就是存在一種極端情況,TLAB只剩下1KB,就會導(dǎo)致后續(xù)的分配可能大多數(shù)對象都需要直接在堆中分配;第二種的就是可能會出現(xiàn)頻繁的廢棄TLAB、頻繁申請TLAB的情況

為了解決這兩個(gè)方案存在的問題,虛擬機(jī)定義了一個(gè)refill_waste的值,這個(gè)值可以翻譯為“最大浪費(fèi)空間”。當(dāng)請求分配的內(nèi)存大于refill_waste的時(shí)候,會選擇在堆內(nèi)存中分配。若小于refill_waste值,則會廢棄當(dāng)前TLAB,重新創(chuàng)建TLAB進(jìn)行對象內(nèi)存分配

那你剛剛說的,幾乎所有對象實(shí)例都存儲在這里,是還有例外嗎?能詳細(xì)解釋下嗎?

是的,親愛的面試官,Java對象實(shí)例和數(shù)組元素不一定都是在堆上分配內(nèi)存,滿足特定的條件的時(shí)候,它們可以在棧上分配內(nèi)存

面試官微微一笑,什么情況呢?

親愛的面試官,是這樣子的,JVM中的Java JIT編譯器有兩個(gè)優(yōu)化,叫做逃逸分析和標(biāo)量替換;

逃逸分析,聽著有點(diǎn)意思,逃,誰逃,什么時(shí)候逃,往哪里逃?

中文維基上對逃逸分析的描述挺準(zhǔn)確的,摘錄如下:

在編譯程序優(yōu)化理論中,逃逸分析是一種確定指針動態(tài)范圍的方法——分析在程序的哪些地方可以訪問到指針。當(dāng)一個(gè)變量(或?qū)ο?在子程序中被分配時(shí),一個(gè)指向變量的指針可能逃逸到其它執(zhí)行線程中,或是返回到調(diào)用者子程序。

大魚白話文版本:

一個(gè)子程序分配了一個(gè)對象并且返回了該對象的指針,那么這個(gè)對象在整個(gè)程序中被訪問的地方無法確定,任何調(diào)用這個(gè)子程序的都可以拿到這個(gè)對象的位置,并且調(diào)用這個(gè)對象,遂,對象逃之;

若指針存儲在全局變量或者其它數(shù)據(jù)結(jié)構(gòu)中,全局變量也可以在子程序之外被訪問到,遂,對象逃之;

若未逃之,則可將方法變量和對象分配到棧上,方法執(zhí)行完之后自動銷毀,不需要垃圾回收的介入,提高系統(tǒng)的性能

簡潔版:

逃逸分析通過分析對象引用的作用域,來決定對象的分配地方(堆 or 棧)

我們一起來看個(gè)例子

  1. public StringBuilder getBuilder1(String a, String b) { 
  2.     StringBuilder builder = new StringBuilder(a); 
  3.     builder.append(b); 
  4.     // builder通過方法返回值逃逸到外部 
  5.     return builder; 
  6. public String getBuilder2(String a, String b) { 
  7.     StringBuilder builder = new StringBuilder(a); 
  8.     builder.append(b); 
  9.     // builder范圍維持在方法內(nèi)部,未逃逸 
  10.     return builder.toString(); 

getBuilder1中的builder對象會通過方法返回值逃逸到方法的外部,而反觀getBuilder2中的builder對象則不會溢出去,作用域只會在方法內(nèi)部,toString方法會new一個(gè)String用來返回,所以沒有逃逸

如果把堆內(nèi)存限制得小一點(diǎn)(比如加上-Xms10m -Xmx10m),關(guān)閉逃逸分析還會造成頻繁的GC,開啟逃逸分析就沒有這種情況,說明逃逸分析確實(shí)降低了堆內(nèi)存的壓力

逃逸分析了之后,就可以直接降低堆內(nèi)存的壓力嗎?(你剛剛說的那個(gè)標(biāo)量替換是什么)

但是,逃逸分析只是棧上內(nèi)存分配的前提,接下來還需要進(jìn)行標(biāo)量替換才能真正實(shí)現(xiàn)。標(biāo)量替換用話不太好說明,直接來看例子吧,形象生動

  1. public static void main(String[] args) throws Exception { 
  2.     long start = System.currentTimeMillis(); 
  3.     for (int i = 0; i < 10000; i++) { 
  4.         allocate(); 
  5.     } 
  6.     System.out.println((System.currentTimeMillis() - start) + " ms"); 
  7.     Thread.sleep(10000); 
  8. public static void allocate() { 
  9.     MyObject myObject = new MyObject(2019, 2019.0); 
  10. public static class MyObject { 
  11.     int a; 
  12.     double b; 
  13.     MyObject(int a, double b) { 
  14.         this.a = a; 
  15.         this.b = b; 
  16.     } 

標(biāo)量,就是指JVM中無法再細(xì)分的數(shù)據(jù),比如int、long、reference等。相對地,能夠再細(xì)分的數(shù)據(jù)叫做聚合量

Java虛擬機(jī)中的原始數(shù)據(jù)類型(int,long等數(shù)值類型以及reference類型等)都不能再進(jìn)一步分解,它們就可以稱為標(biāo)量。相對的,如果一個(gè)數(shù)據(jù)可以繼續(xù)分解,那它稱為聚合量,Java中最典型的聚合量是對象

如果逃逸分析證明一個(gè)對象不會被外部訪問,并且這個(gè)對象是可分解的,那程序真正執(zhí)行的時(shí)候?qū)⒖赡懿粍?chuàng)建這個(gè)對象,而改為直接創(chuàng)建它的若干個(gè)被這個(gè)方法使用到的成員變量來代替。拆散后的變量便可以被單獨(dú)分析與優(yōu)化,可以各自分別在棧幀或寄存器上分配空間,原本的對象就無需整體分配空間了

仍然考慮上面的例子,MyObject就是一個(gè)聚合量,因?yàn)樗蓛蓚€(gè)標(biāo)量a、b組成。通過逃逸分析,JVM會發(fā)現(xiàn)myObject沒有逃逸出allocate()方法的作用域,標(biāo)量替換過程就會將myObject直接拆解成a和b,也就是變成了:

  1. static void allocate() { 
  2.     int a = 2019; 
  3.     double b = 2019.0; 

可見,對象的分配完全被消滅了,而int、double都是基本數(shù)據(jù)類型,直接在棧上分配就可以了。所以,在對象不逃逸出作用域并且能夠分解為純標(biāo)量表示時(shí),對象就可以在棧上分配

除了這些之后,你還知道哪些優(yōu)化嗎?

emmm,先思索一下(即使知道,也要稍加思考!

除此之外,JVM還有一個(gè)同步消除(鎖消除):鎖消除是Java虛擬機(jī)在JIT編譯是,通過對運(yùn)行上下文的掃描,去除不可能存在共享資源競爭的鎖,通過鎖消除,可以節(jié)省毫無意義的請求鎖時(shí)間。

鎖消除基于分析逃逸基礎(chǔ)之上,開啟鎖消除必須開啟逃逸分析

線程同步本身比較耗,如果確定一個(gè)對象不會逃逸出線程,無法被其它線程訪問到,那該對象的讀寫就不會存在競爭,對這個(gè)變量的同步措施就可以消除掉。單線程中是沒有鎖競爭。(鎖和鎖塊內(nèi)的對象不會逃逸出線程就可以把這個(gè)同步塊取消)

  1. public synchronized String append(String str1, String str2) { 
  2.     StringBuffer sBuf = new StringBuffer(); 
  3.     // append方法是同步操作 
  4.     sBuf.append(str1); 
  5.     sBuf.append(str2); 
  6.     return sBuf.toString(); 

從源碼中可以看出,append方法用了synchronized關(guān)鍵詞,它是線程安全的。但我們可能僅在線程內(nèi)部把StringBuffer當(dāng)作局部變量使用

這時(shí)我們可以通過編譯器將其優(yōu)化,將鎖消除,前提是java必須運(yùn)行在server模式,server模式會比client模式作更多的優(yōu)化,同時(shí)必須開啟逃逸分析

說一說剛剛說的這些的參數(shù)嗎

我個(gè)乖乖兔,這我哪記得,不過得虧我昨天剛讀了大魚的文章,順便學(xué)習(xí)了下

逃逸分析:-XX:+DoEscapeAnalysis開啟逃逸分析(jdk1.8默認(rèn)開啟,其它版本未測試);-XX:-DoEscapeAnalysis 關(guān)閉逃逸分析

同步消除:-XX:+EliminateLocks開啟鎖消除(jdk1.8默認(rèn)開啟,其它版本未測試);-XX:-EliminateLocks 關(guān)閉鎖消除

標(biāo)量替換:-XX:+EliminateAllocations開啟標(biāo)量替換(jdk1.8默認(rèn)開啟,其它版本未測試);-XX:-EliminateAllocations 關(guān)閉標(biāo)量替換

那你平時(shí)是用哪些參數(shù)優(yōu)化內(nèi)存的?

一般我個(gè)人接觸到的有兩類參數(shù):內(nèi)存調(diào)整參數(shù)、垃圾收集器調(diào)整參數(shù)

內(nèi)存調(diào)整參數(shù):-Xmx堆內(nèi)存最大值;-Xms堆內(nèi)存最小值;-Xmn堆新生代的大小;-Xss設(shè)置線程棧的大小;-XX:NewRatio指定堆中的老年代和新生代的大小比例, 不過使用CMS收集器的時(shí)候這個(gè)參數(shù)會失效

關(guān)于方法區(qū)的參數(shù),在JDK8之前,用-XX:PermSize和-XX:MaxPermSize來分別設(shè)置方法區(qū)的最小值和最大值;JDK8以及之后不再使用這個(gè)參數(shù)來設(shè)置方法區(qū)了,改為-XX:MeatspaceSize和-XX:MaxMetaspaceSize來設(shè)置方法區(qū)的大小了,Max參數(shù)主要就是防止某些情況導(dǎo)致Metaspace無限的使用本地內(nèi)存,若超過設(shè)定值就會觸發(fā)Full GC,所以需要根據(jù)系統(tǒng)內(nèi)存大小來動態(tài)的改變此值

垃圾收集器的調(diào)整參數(shù)我就不舉例子了,垃圾收集器調(diào)整參數(shù)就是設(shè)置JVM的垃圾收集器或者調(diào)整收集器的一些優(yōu)化參數(shù),說實(shí)話大魚也不沒那么了解,這種參數(shù)我一般都是用到的時(shí)候去查資料,也沒啥必要了解那么細(xì),專業(yè)人員除外

你剛剛說了堆內(nèi)存中有個(gè)8:1:1,出于什么考慮這樣設(shè)計(jì)的呢

有的對象朝生夕死,有的對象可能會活很久很久,有的對象很小,有的對象可能會很大,每個(gè)對象的特點(diǎn)不一樣,分配的堆內(nèi)存地方不一樣,也就對應(yīng)著不同的回收策略以及垃圾回收器,年輕代就是存放那種使用完就立馬回收的對象,而老年代則用來存放那些長期駐留在內(nèi)存中的對象

 

其實(shí)說白了,就是根據(jù)多種對象的特點(diǎn)來設(shè)計(jì)出多種了回收策略,而對于整塊內(nèi)存使用一種回收策略是不友好的,所以根據(jù)對象的特點(diǎn)來將堆內(nèi)存拆分開,然后對于每塊內(nèi)存采用不同的回收策略

虛擬機(jī)棧和本地內(nèi)存棧

Java虛擬機(jī)棧屬于線程私有的,生命周期和線程相同;虛擬機(jī)棧是Java方法執(zhí)行的內(nèi)存模型,描述的方法的執(zhí)行過程;每個(gè)方法被執(zhí)行的時(shí)候都會同時(shí)創(chuàng)建一個(gè)棧幀結(jié)構(gòu),用于存儲局部變量表、操作數(shù)棧、動態(tài)鏈接、方法出口等信息,棧里面會包含很多的

棧幀,可以認(rèn)為每一個(gè)方法的調(diào)用直到執(zhí)行完成對應(yīng)這一個(gè)棧幀的入棧和出棧的過程

虛擬機(jī)棧的棧幀里面都包含什么呢?

主要是包含局部變量表、操作數(shù)棧、動態(tài)鏈接、方法出口這些,接著我們來看下每一部分的作用

這些大家不需要死記硬背的哦,需要大家理解記憶,最重要的是理解每一部分的作用,下面可能第一次接觸的會比較枯燥,keep

局部變量表:存放了編譯期可知的各種基本數(shù)據(jù)類型、對象引用(reference類型,它不等同于對象本身,它可能是一個(gè)指向?qū)ο笃鹗嫉刂返囊弥羔?,也可能指向一個(gè)代表對象的句柄或者其他與此對象相關(guān)的位置)。

操作數(shù)棧:一個(gè)后進(jìn)先出的操作數(shù)棧,主要用于保存計(jì)算過程的中間結(jié)果,同時(shí)作為計(jì)算過程中變量臨時(shí)的存儲空間。

操作數(shù)棧就是JVM執(zhí)行引擎的一個(gè)工作區(qū),當(dāng)一個(gè)方法剛開始執(zhí)行的時(shí)候,一個(gè)新的棧幀也會隨之被創(chuàng)建出來,這個(gè)方法的操作數(shù)棧是空的。每一個(gè)操作數(shù)棧都會擁有一個(gè)明確的棧深度用于存儲數(shù)值,其所需的最大深度在編譯期就定義好了,保存在方法的Code屬性中,為maxstack的值。

動態(tài)鏈接:在Java源文件被編譯到字節(jié)碼文件中時(shí),所有的變量和方法引用都作為符號引用(symbolic Reference)保存在class文件的常量池里。比如:描述一個(gè)方法調(diào)用了另外的其他方法時(shí),就是通過常量池中指向方法的符號引用來表示的,那么動態(tài)鏈接的作用就是為了將這些符號引用轉(zhuǎn)換為調(diào)用方法的直接引用。

方法出口:存放調(diào)用該方法的pc寄存器的值。一個(gè)方法的結(jié)束,有兩種方式:正常執(zhí)行完成、出現(xiàn)未處理的異常,非正常退出

無論通過哪種方式退出,在方法退出后都返回到該方法被調(diào)用的位置。方法正常退出時(shí),調(diào)用者的pc計(jì)數(shù)器的值作為返回地址,即調(diào)用該方法的指令的下一條指令的地址。而通過異常退出的,返回地址是要通過異常表來確定,棧幀中一般不會保存這部分信息。

棧的深度問題

在Java虛擬機(jī)規(guī)范中,對這個(gè)區(qū)域規(guī)定了兩種異常狀況:

如果線程請求的棧深度大于虛擬機(jī)所允許的深度,將拋出StackOverflowError異常;如果虛擬機(jī)??梢詣討B(tài)擴(kuò)展(當(dāng)前大部分的Java虛擬機(jī)都可動態(tài)擴(kuò)展,只不過Java虛擬機(jī)規(guī)范中也允許固定長度的虛擬機(jī)棧),當(dāng)擴(kuò)展時(shí)無法申請到足夠的內(nèi)存時(shí)會拋出OutOfMemoryError異常。

那本地方法棧是干什么的?

本地方法棧(Native Method Stacks)與虛擬機(jī)棧所發(fā)揮的作用是非常相似的,其區(qū)別不過是虛擬機(jī)棧為虛擬機(jī)執(zhí)行Java方法(也就是字節(jié)碼)服務(wù),而本地方法棧則是為虛擬機(jī)使用到的Native方法服務(wù)。

虛擬機(jī)規(guī)范中對本地方法棧中的方法使用的語言、使用方式與數(shù)據(jù)結(jié)構(gòu)并沒有強(qiáng)制規(guī)定,因此具體的虛擬機(jī)可以自由實(shí)現(xiàn)它。甚至有的虛擬機(jī)(譬如Sun HotSpot虛擬機(jī))直接就把本地方法棧和虛擬機(jī)棧合二為一。與虛擬機(jī)棧一樣,本地方法棧區(qū)域也會拋出StackOverflowError和OutOfMemoryError異常。

Java虛擬機(jī)棧于管理Java方法的調(diào)用,而本地方法棧(Native Method Stack)用于管理本地方法的調(diào)用。本地方法棧,也是線程私有的。

方法區(qū)

方法區(qū)(Method Area)與Java堆一樣,是各個(gè)線程共享的內(nèi)存區(qū)域,它用于存儲已被虛擬機(jī)加載的類信息、常量、靜態(tài)變量、即時(shí)編譯器編譯后的代碼等數(shù)據(jù)。

方法區(qū)在原來被習(xí)慣性的稱之為永久代,但是在JDK1.8中永久代已經(jīng)不存在了,存儲的類信息、編譯之后的代碼數(shù)據(jù)都移到了元空間,而元空間并沒有在堆中,而是直接占用的本地內(nèi)存

元空間和永久代本質(zhì)是類似的,其實(shí)都是對JVM規(guī)范中的方法區(qū)的實(shí)現(xiàn),元空間并不在虛擬機(jī)中,而是使用本地內(nèi)存。因此,默認(rèn)情況下,元空間的大小僅受本地內(nèi)存限制

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

程序計(jì)數(shù)器啊,聽名字其實(shí)就知道了,主要作用就是計(jì)數(shù)的,但是這里的計(jì)數(shù)并不是計(jì)算數(shù)量,而是記下一條的字節(jié)碼指令

程序計(jì)數(shù)器占一小塊內(nèi)存空間,就是當(dāng)前線程的執(zhí)行的字節(jié)碼的行號指示器,字節(jié)碼解釋器工作時(shí)就是通過改變這個(gè)計(jì)數(shù)器的值來選取下一條需要執(zhí)行的字節(jié)碼指令,分支、循環(huán)、跳轉(zhuǎn)、異常處理、線程恢復(fù)等基礎(chǔ)功能都需要依賴這個(gè)計(jì)數(shù)器來完成。

那程序計(jì)數(shù)器是線程私有還是公有?

相信聰明的養(yǎng)魚仔肯定已經(jīng)猜到了,當(dāng)然是私有的嘞

Java虛擬機(jī)多線程是通過線程輪流切換并分配處理器執(zhí)行時(shí)間的方式來實(shí)現(xiàn)的,在任何一個(gè)確定的時(shí)刻,一個(gè)處理器(對于多核處理器來說是一個(gè)內(nèi)核)只會執(zhí)行一條線程中的指令。因此,為了線程切換后能恢復(fù)到正確的執(zhí)行位置,每條線程都需要有一個(gè)獨(dú)立的程序計(jì)數(shù)器,各條線程之間的計(jì)數(shù)器互不影響,獨(dú)立存儲,我們稱這類內(nèi)存區(qū)域?yàn)?ldquo;線程私有”的內(nèi)存。

如果線程正在執(zhí)行的是一個(gè)Java方法,這個(gè)計(jì)數(shù)器記錄的是正在執(zhí)行的虛擬機(jī)字節(jié)碼指令的地址,如果正在執(zhí)行的是Natvie方法,這個(gè)計(jì)數(shù)器值則為空(Undefined)。此內(nèi)存區(qū)域是唯一一個(gè)在Java虛擬機(jī)規(guī)范中沒有規(guī)定任何OutOfMemoryError情況的區(qū)域。

我愛總結(jié)

好了,今天就先聊到這了,天也不早了,你早點(diǎn)回家休息吧,好好準(zhǔn)備準(zhǔn)備明天下午來繼續(xù)下一輪面試吧

好的,尊敬的面試官(逃

回到家之后我就拿出我的小本本一頓總結(jié),跟著大魚一起來看看吧,養(yǎng)魚仔們

 

  • 堆:線程共享,主要用于分配實(shí)例對象,但由于逃逸分析的存在也不是完全在堆上分配,可能在棧上分配;逃逸分析是個(gè)基礎(chǔ),標(biāo)量替換和鎖消除正是基礎(chǔ)逃逸分析的優(yōu)化;堆中還有個(gè)TLAB分配,屬于線程私有,但又不是完全意義上的私有
  • 棧:線程私有,虛擬機(jī)棧主要是用于Java方法的執(zhí)行,每個(gè)棧幀對應(yīng)一個(gè)方法的入棧和出棧,包含局部變量、操作數(shù)棧、動態(tài)鏈接和方法出口這些;本地方法棧則是用于執(zhí)行本地方法的
  • 方法區(qū):線程共享,存放加載的類信息、常量、靜態(tài)變量以及即時(shí)編譯器編譯之后的代碼
  • 程序計(jì)數(shù)器:線程私有,存放每個(gè)線程接下來要執(zhí)行的指令

 

責(zé)任編輯:武曉燕 來源: 大魚仙人
相關(guān)推薦

2022-05-24 08:03:28

InnoDBMySQL數(shù)據(jù)

2021-12-02 08:19:06

MVCC面試數(shù)據(jù)庫

2021-05-20 08:54:16

Go面向對象

2020-04-16 08:22:11

HTTPS加解密協(xié)議

2010-08-23 15:06:52

發(fā)問

2021-09-01 07:21:41

面試官開發(fā)讀寫鎖

2020-08-10 07:58:18

異步編程調(diào)用

2021-06-03 08:55:54

分布式事務(wù)ACID

2022-04-10 18:10:24

CURD鏈表

2022-10-17 00:04:30

索引SQL訂單

2022-10-08 00:08:00

apiESFacebook

2022-02-09 09:37:54

ReactorNettyI/O

2020-10-26 07:07:50

線程安全框架

2015-08-13 10:29:12

面試面試官

2020-12-03 07:39:50

HashMap底層數(shù)據(jù)

2020-12-01 11:50:49

數(shù)據(jù)庫Redis面試

2021-09-29 19:17:51

編碼URLEncodeGBK

2022-04-01 07:52:42

JavaScript防抖節(jié)流

2021-05-08 07:53:33

面試線程池系統(tǒng)

2021-05-19 08:17:35

秒殺場景高并發(fā)
點(diǎn)贊
收藏

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