Java內存結構詳解

Java把內存分紅:棧內存,堆內存,方法區,本地方法區和寄存器等。
  下面分別介紹棧內存,堆內存,方法區各自一些特性:
  一、棧內存
  (1)一些基本類型的變量和對象的引用變量都是在函數的棧內存中分配。
  (2)每一個棧中的數據(原始類型和對象引用)都是私有的,其餘棧不能訪問。
  (3)棧分爲3個部分:基本類型變量區、執行環境上下文、操做指令區(存放操做指令)。
  (4)當在一段代碼塊中定義一個變量時,java就在棧中爲這個變量分配內存空間,當超過變量的做用域後
  ,java會自動釋放掉爲該變量分配的內存空間,該內存空間能夠馬上被另做他用。
  (5)當數據使用完,所佔空間會自動釋放。
  二、堆內存
  (1)堆內存用於存放由new建立的對象和數組。
  (2)每個實體都有一個內存地址值
  (3)實體中的變量都有默認初始化值
  (4)實體再也不被使用,會在不肯定的時間內被垃圾回收器回收
  補充:數組和對象在沒有引用變量指向它的時候,才變成垃圾,不能再被使用,可是仍然佔着內存,在隨後的一個不肯定的時間被垃圾回收器釋放掉。這個也是java比較佔內存的主要緣由,實際上,棧中的變量指向堆內存中的變量,這就是 Java 中的指針!
  三、方法區
  1.又叫靜態區,跟堆同樣,被全部的線程共享。方法區包含全部的class和static變量。
  2.方法區中包含的都是在整個程序中永遠惟一的元素,如class,static變量。
  方法區存放裝載的類數據信息包括:
  (1)基本信息:
  1)每一個類的全限定名
  2)每一個類的直接超類的全限定名(可約束類型轉換)
  3)該類是類仍是接口
  4)該類型的訪問修飾符
  5)直接超接口的全限定名的有序列表
  (2)每一個已裝載類的詳細信息:
  1)運行時常量池:
  存放該類型所用的一切常量(直接常量和對其它類型、字段、方法的符 號引用),它們以數組形式經過索引被訪問,是外部調用與類聯繫及類型對象化的橋樑。它是類文件(字節碼)常量池的運行時表示。(還有一種靜態常量池,在字節碼文件中)。
  2)字段信息:
  類中聲明的每個字段的信息(名,類型,修飾符)。
  3)方法信息:
  類中聲明的每個方法的信息(名,返回類型,參數類型,修飾符,方法的字節碼和異常表)。
  4)靜態變量
  5)到類 classloader 的引用:即到該類的類裝載器的引用。
  6)到類 class 的引用: 虛擬機爲每個被裝載的類型建立一個 class 實例, 用來表明這個被裝載的類
  以上爲棧內存,堆內存,方法區的一些特性,其中
  棧有一個很重要的特殊性,就是存在棧中的數據能夠共享。假設咱們同時定義:
  int a = 5;
  int b = 5;
  編譯器先處理int a = 5;首先它會在棧中建立一個變量爲a的引用,而後查找棧中是否有5這個值,若是沒找到,就將5存放進來,而後將a指向5.
  接着處理int b = 5;在建立完b的引用變量後,由於在棧中已經有5這個值,便將b直接指向5.這樣,就出現了a與b同時均指向5的狀況。
  這時,若是再令a=8;那麼編譯器會從新搜索棧中是否有8值,若是沒有,則將8存放進來,並令a指向8;若是已經有了,則直接將a指向這個地址。所以a值的改變不會影響到b的值。
  注意:這種數據的共享與兩個對象的引用同時指向一個對象的這種共享是不一樣的,由於這種狀況a的修改並不會影響到b, 它是由編譯器完成的,它有利於節省空間。而一個對象引用變量修改了這個對象的內部狀態,會影響到另外一個對象引用變量。
  下面舉例說明Java程序在內存中的分配:
  拿String舉例,其中String是一個特殊的包裝類數據。能夠用:
  String str = new String("abc");
  String str = "abc";
  兩種的形式來建立,第一種是用new()來新建對象的,它會在存放於堆中。每調用一次就會建立一個新的對象。
  而第二種是先在棧中建立一個對String類的對象引用變量str,而後查找棧中有沒有存放"abc",若是沒有,則將"abc"存放進棧,並令str指向"abc",若是已經有"abc" 則直接令str指向"abc".
  比較類裏面的數值是否相等時,用equals()方法;當測試兩個包裝類的引用是否指向同一個對象時,用==,下面用例子說明上面的理論。
  String str1 = "abc";
  String str2 = "abc";
  System.out.println(str1==str2); //true
  //能夠看出str1和str2是指向同一個對象的。
  String str1 =new String ("abc");
  String str2 =new String ("abc");
  System.out.println(str1==str2); // false
  //用new的方式是生成不一樣的對象。每一次生成一個。
  所以用第一種方式建立多個"abc"字符串,在內存中其實只存在一個對象而已。這種寫法有利與節省內存空間。 同時它能夠在必定程度上提升程序的運行速度,由於JVM會自動根據棧中數據的實際狀況來決定是否有必要建立對象。
  而對於String str = new String("abc");的代碼,則一律在堆中建立新對象,而無論其字符串值是否相等,是有必要建立新對象,從而加劇了程序的負擔。
  另外一方面, 要注意: 咱們在使用諸如String str = "abc";的格式定義類時,老是想固然地認爲,建立了String類的對象str.小心陷阱!對象可能並無被建立!而可能只是指向一個先前已經建立的對象。只有經過new()方法才能保證每次都建立一個新的對象。java

相關文章
相關標籤/搜索