編輯:關於Android編程
java虛擬機基本結構:
JVM是一個內存中的虛擬機,那它的存儲就是內存了,我們寫的所有類、常量、變量、方法都在內存中,因此明白java虛擬機的內存分配非常重要,本部分主要講解java虛擬機內存分配。
本部分會從概念上介紹java虛擬機內存的各個區域,講解這些區域的作用、服務對象以及其中可能產生的問題。
下面通過一個簡單的示例,來展示java堆、方法區和java棧之間的關系。
public class SimpleHeap { private int id; public SimpleHeap(int id) { this.id = id; } public static void main(String[] args) { SimpleHeap s1 = new SimpleHeap(1); SimpleHeap s2 = new SimpleHeap(2); s1.show(); s2.show(); } public void show() { System.out.println("my id is" + id); } }
??程序計數器,是一塊較小的內存區域。它的作用可以看做是當前線程所執行的字節碼的行號指示器。在虛擬機的概念模型裡,字節碼解釋器工作時就是通過改變這個計數器的值來選取下一條需要執行的字節碼指令。分支、循環、跳轉、異常處理、線程恢復等基礎功能都需要依賴這個計數器來完成。
??虛擬機棧描述的是java方法執行的內存模型:每個方法在執行時都會創建一個棧幀用於存儲局部變量表、操作數棧、動態鏈接、方法出口燈信息。每個方法被調用直至執行完成的過程,就對應著一個棧幀在虛擬機棧中從入棧到出棧的過程。
??經常有人把java內存區域分為堆內存和棧內存,這種分法比較粗糙,java內存區域的劃分實際上遠比這復雜。這種劃分方式的流行只能說明大多數程序員最關注的,與對象內存分配關系最密切的內存區域是這兩塊。其中所指的棧就是這裡的棧,或者更具體說是虛擬機棧中的局部變量表部分。
??在java棧中保存的主要內容為棧幀。每一次函數調用,都會有一個對應的棧幀被壓入java棧,每一個函數調用結束,都會有一個棧幀被彈出java棧。如下圖所示,函數1對應棧幀1,函數2對應棧幀2,依次類推。函數1中調用函數2,函數2中調用函數3,函數3中調用函數4.當函數1被調用時,棧幀1入棧,當函數2被調用時,棧幀2入棧;當函數3被調用時,棧幀3入棧;當函數4被調用時,棧幀4入棧。當前正在執行的函數所對應的幀就是當前的幀(位於棧頂),它保存著當前函數的局部變量、中間結果等數據。
??當函數返回時,棧幀從java中被彈出。java方法有兩種返回函數的方式,一種是正常的函數返回,使用return指令,另外一種是拋出異常。不管使用哪種方式,都會導致棧幀被彈出。
備注:每次函數調用都會生成對應的棧幀,如果請求的棧深度大於最大的可用棧深度時,系統就會拋出stackoverflowerror棧溢出錯誤。
在一個棧幀中,至少要包含局部變量表、操作數棧和幀數據區等幾個部分。
1)局部變量表
局部變量表存放了編譯器可知的各種基本數據類型(boolean,byte,char,short,int,float,long,double)、對象引用(reference類型,他不等同於對象本身,根據不同的虛擬機實現,它可能是一個指向對象起始地址的引用指針,也可能指向一個代表對象的句柄或者其他與此對象相關的位置)和return address類型(指向一條字節碼指令的地址)。
returnadress類型(A給命令於B,b反饋於A,這個時候A即為返回地址。)
局部變量表所需的內存空間在編譯期間完成分配,當進入一個方法時,這個方法需要在幀中分配多大的局部變量空間是完全確定的,在方法運行期間不會改變局部變量表的大小。
局部變量表用於保存函數的參數以及局部變量。局部變量表中的變量只在當前函數調用中有效,當函數調用結束後,隨著函數棧幀的銷毀,局部變量表也就隨之銷毀。
由於局部變量表在棧幀之中,因此,如果函數的參數和局部變量較多,會使得局部變量表膨脹,從而每一次函數調用都會占用更多的棧空間,最終導致函數的嵌套調用次數減少。
2)操作棧
操作數棧主要用於保存計算過程中的中間結果,同時作為計算過程中變量臨時的存儲空間。
操作數棧也是一個先進後出的數據結構,只支持入棧和出棧兩種操作。
把局部變量區的東西拿過來入棧,出棧等等
a =2;
b = 3;
c = a + b;
return c;
c = a +b 時會把局部變量表的a 和 b拿過來入棧,進行運算
3)動態鏈接
4)方法出口
??本地方法棧與虛擬機棧所發揮的作用是類似的,其區別不過是虛擬機棧為虛擬機執行java方法(也就是字節碼)服務,而本地方法棧則是為虛擬機使用到的native方法服務。
??對於大多數應用來說,java堆是java虛擬機所管理的內存中最大的一塊。java堆是被所有線程共享的一塊內存區域,在虛擬機啟動時創建。此內存區域的唯一目的是存放對象實例,幾乎所有的對象實例都在這裡分配內存。
??java堆是垃圾回收器管理的主要區域,因此很多時候也被稱為“GC堆”,如果從內存回收的角度看,由於現在收集器基本都是采用的分代收集算法,所以java堆中還可以細分為:新生代和老生代;再細致一點的有Eden空間,From Survivor空間、To Survivor空間等。不過無論如何劃分,都與存放內容無關,無論哪個區域,存儲的都仍然是對象實例,進一步劃分的目的是為了更好的回收內存,或者更快的分配內存。
??是各個線程共享的內存區域,它用於存放已經被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據。它有一個別名NonHeap(非堆),目的應該是與java堆區分開來。方法區的大小決定了系統可以保存多少個類。
??運行時常量池是方法區的一部分。Class文件中除了有類的版本、字段,方法、接口等信息外,還有一項信息是常量池,用於存放編譯期生成的各種字面量和符號引用,這部分內容將在類加載後存放到方法區的運行時常量池中。
常量池之中主要存放兩大類常量:字面量、符號引用。字面量比較接近於java語言層面的常量概念,如文本字符串、被聲明為final的常量值等。而符號引用則屬於編譯原理方面的概念,包括下面三類常量:
- 類和接口的全限定名
- 字段的名稱和描述符
- 方法的名稱和描述符
被更新了,自己之前一直以為只有字面量
??直接內存並不是虛擬機運行時數據區的一部分,也不是java虛擬機規范中定義的內存區域。但是該部分內存在被頻繁的使用,而且也可能導致oom異常出現。
??在jdk1.4中新加入了NIO類,引入了一種基於通道(channel)與緩沖區(buffer)的I/O方式,它可以使用native函數庫直接分配堆外內存,然後通過一個存儲在java堆中的DirectByteBuffer對象為這塊內存的引用進行操作。這樣能在一些場景中顯著提高性能,因為避免了在java堆和native堆中來回復制數據。
??顯然,本機直接內存的分配不會受到java堆大小的限制,但是受限於本機總內存的大小,同樣會產生OOM。
1.android為什麼要簽名 所有的Android應用程序都要求開發人員用一個證書進行數字簽名,anroid系統不會安裝沒有進行簽名的由於程序。平時我們的程序可
一、實現思路1、在build.gradle中添加依賴,例如:compile com.android.support:support-v4:23.4.0compile co
開發者可利用SDK提供的接口,使用百度為您提供的基礎地圖數據。目前百度地圖SDK所提供的地圖等級為3-21級,所包含的信息有建築物、道路、河流、學校、公園等內容。 V3.
先來看看效果圖當你點擊菜單可以更改圖標,例如點擊happy,首頁就會變一個笑臉,這個實現的過程超級簡單你需要使用ToolBar與DrawableLayout兩個比較新的控