月初的時候我的網站到期了,不想再折騰從新建站了,之後仍是來第三方博客寫文章吧,能夠省去不少問題。以前寫的文章也不是不少,備份懶得作了,從頭開始吧。博文僅僅是用來記錄和學習總結,若有錯誤之處請幫忙指正!程序員
今天想說說JVM內存結構的問題,說到JVM你們確定首先想到的是棧和堆。的確,這兩塊說是JVM內存結構最重要的部分也不爲過。先來簡單介紹一下吧,數組
內存結構按照私有和共享劃分方式以下:數據結構
線程私有:棧區、本地方法棧、程序計數器學習
線程共享:堆區、方法區測試
其餘不說了,重點說說棧和堆優化
棧:網站
棧的特色就是快。每一個線程對應一個棧,每一個棧含有1個或多個棧幀,棧幀用來存放方法的局部變量表、操做數棧、動態連接、returnAddress等信息,每運行一個方法就會建立一個棧幀,從方法運行到結束對應着棧幀在棧區裏面入棧和出棧的過程。線程
局部變量表包含兩類數據結構,一是八大基本類型,byte short int long float double char boolean; 第二類是reference類型,佔用空間是4byte,不論是對象是大是小,操控它僅須要用一個4byte的變量便可,並且能夠按需銷燬,這足以體現棧堆分離的好處。指針
棧空間是能夠重複利用的,遇到左括號入棧,遇到右括號出棧,咱們當系統進行遞歸調用時,系統會連續屢次執行入棧操做,直到最深處才執行出棧操做,這就可能致使棧空間不足,StackOverFlowError異常,所以遇到該異常通常不是對象太大致使的,可能是由於不正確遞歸或棧空間不足以容納致使。在棧區還可能會遇到OOM異常,當線程過多時或分配空間太小時,若是沒法申請到足夠內存時,便會報OOM異常(棧區OOM異常的緣由暫不肯定也爲碰見過,只是周志明JVM書中提到棧區OOM異常,上網也未查到)。JVM調優:經過-Xss來控制棧空間大小。對象
堆:
堆是JVM內存中最大的一塊,是用來爲對象和數組元素分配空間的地方,而對象的引用變量和數組引用都是在棧中存放的。「幾乎全部的對象都在這裏建立」,那麼什麼狀況下對象不在堆中建立呢?隨着JIT編譯器的發展,在編譯期間,若是JIT經逃逸分析後發現對象沒有逃逸出方法,那麼該對象坑會在棧上分配內存而不是堆,可是也不絕對。測試:爲JVM分配足夠空間,關閉逃逸分析,建立一百萬個User對象,jmap命令發現堆中建立了一百萬個對象,開啓逃逸分析,發現堆中的對象變成了八萬個,也就是說JIT編譯器確實會將對象分配在棧裏,但並不絕對。
使用逃逸分析,編譯器能夠針對分析結果作如下優化:
一、同步省略(鎖消除優化):若是一個對象被發現只能被一個線程訪問,那麼能夠不考慮該對象的同步;
二、棧上分配對象;若是一個對象在子程序中被分配,要是指向該對象的指針永遠不會逃逸,對象可能會在棧中被分配,而不是在堆中;
三、分離對象或標量替換:有的對象可能不須要連續的內存結構,能夠將該對象的部分或所有存儲到CPU的寄存器中。
逃逸分析:-XX:+/-DoEscapeAnalysis
關於堆的分代和垃圾收集下次再講。
順帶講一下,參數傳遞的時候,Java是傳值仍是傳引用?這個問題相信每一個程序員都會思考過,也確定遇到過由此引起的問題。
要說明這個問題,首先要說明兩點:一是不要和C語言類比,Java沒有指針的概念;二是程序運行永遠都是在棧中進行,於是參數傳遞時涉及到的只會是基本數據類型和引用類型,理論上來講不會涉及到對象自己。而Java中沒有指針的概念,所以Java能夠說是傳值調用,當參數是引用類型時傳遞的是引用變量的值;可是當進入被調用方法時,被傳遞的這個引用的值,被程序解釋(或者查找)到堆中的對象,這個時候纔對應到真正的對象,這個時候若是對其進行修改,修改的並非引用自己,而是對象的屬性,因此對對象的修改會保持。程序參數傳遞時,被傳遞的值自己都是不能進行修改的,可是,若是這個值是一個引用,則能夠修改這個引用背後的東西。