java內存的分配和管理

經常使用的三個內存空間  html

    棧內存 ,堆內存 ,方法區程序員

    棧內存存儲的內容: 局部變量、 函數(棧中的局部變量,須要手動賦值。當變量,或者函數執行完畢,就自動被釋放)        web

    堆內存,存儲的內容 :全局變量、數據容器、創建的對象(堆內存中存儲的容器,不會自動釋放,由垃圾回收機制GC不定時自動清理)   數組

   方法區存儲的內容 :class類文件、靜態、常量 jvm

 
JAVA內存分配與管理是Java的核心技術之一,以前咱們曾介紹過Java的內存管理與內存泄露以及Java垃圾回收方面的知識,今天咱們再次深刻Java核心,詳細介紹一下Java在內存分配方面的知識。通常Java在內存分配時會涉及到如下區域:
寄存器:咱們在程序中沒法控制

棧:存放基本類型的數據和對象的引用,但對象自己不存放在棧中,而是存放在堆中

堆:存放用new產生的數據

靜態域:存放在對象中用static定義的靜態成員

常量池:存放常量


非RAM存儲:硬盤等永久存儲空間

Java內存分配中的棧

在函數中定義的一些基本類型的變量數據和對象的引用變量都在函數的棧內存中分配。 當在一段代碼塊定義一個變量時,Java就在棧中爲這個變量分配內存空間當該變量退出該做用域後Java會自動釋放掉爲該變量所分配的內存空間,該內存空間能夠當即被另做他用。

Java內存分配中的堆 

堆內存用來存放由new建立的對象和數組。 在堆中分配的內存由Java虛擬機的自動垃圾回收器來管理 

在堆中產生了一個數組或對象後,還能夠在棧中定義一個特殊的變量,讓棧中這個變量的取值等於數組或對象在堆內存中的首地址,棧中的這個變量就成了數組或對象的引用變量。 引用變量就至關因而 爲數組或對象起的一個名稱,之後就能夠在程序中使用棧中的引用變量來訪問堆中的數組或對象。引用變量就至關因而爲數組或者對象起的一個名稱。

引用變量是普通的變量,定義時在棧中分配,引用變量在程序運行到其做用域以外後被釋放。而數組和對象自己在堆中分配,即便程序運行到使用 new 產生數組或者對象的語句所在的代碼塊以外,數組和對象自己佔據的內存不會被釋放,數組和對象在沒有引用變量指向它的時候,才變爲垃圾,不能在被使用,但仍然佔據內存空間不放,在隨後的一個不肯定的時間被垃圾回收器收走(釋放掉)。這也是 Java 比較佔內存的緣由。
實際上,棧中的變量指向堆內存中的變量,這就是Java中的指針!函數

常量池 (constant pool)

常量池指的是在編譯期被肯定,並被保存在已編譯的.class文件中的一些數據。除了包含代碼中所定義的各類基本類型(如int、long等等)和對象型(如String及數組)的常量值(final)還包含一些以文本形式出現的符號引用,好比:

類和接口的全限定名;

字段的名稱和描述符;

方法和名稱和描述符。測試

虛擬機必須爲每一個被裝載的類型維護一個常量池。常量池就是該類型所用到常量的一個有序集和,包括直接常量(string,integer和 floating point常量)和對其餘類型,字段和方法的符號引用。
棧內存和堆內存比較

  棧與堆都是 Java 用來在內存中存放數據的地方。與 C++不一樣,Java自動管理棧和堆,程序員不能直接地設置棧或堆。
Java 的堆是一個運行時數據區,對象從中分配空間。堆的優點是能夠動態地分配內存大小,生存期也沒必要事先告訴編譯器,由於它是在運行時動態分配內存的。Java 的垃圾收集器會自動收走這些再也不使用的數據。但缺點是,因爲要在運行時動態分配內存,存取速度較慢 
棧的優點是,存取速度比堆要快,僅次於寄存器,棧數據能夠共享。但缺點是,存在棧中的數據大小與生存期必須是肯定的, 缺少靈活性。棧中主要存放一些基本類型的變量 (int,short, long, byte, float, double, boolean, char)和對象句柄(即對象的引用)。 
棧有一個很重要的特殊性,就是存在棧中的數據能夠共享。假設咱們同時定義:
int a = 3;
int b = 3;
編譯器先處理 int a = 3;首先它會在棧中建立一個變量爲 a 的引用,而後查找棧中是 否有 3 這個值,若是沒找到,就將 3存放進來,而後將 a 指向 3。接着處理 int b = 3;在建立完 b 的引用變量後,
由於在棧中已經有 3 這個值,便將 b 直接指向 3。這樣,就出現了a 與 b 同時均指向 3 的狀況。
這時,若是再令 a=4;那麼編譯器 會從新搜索棧中是否有 4 值,若是沒有,則將 4 存 放進來,並令 a 指向 4;若是已經有了,則直接將 a 指向這個地址。所以 a 值的改變不會影響到 b 的值。
要注意這種數據的共享與兩個對象的引用同時指向一個對象的這種共享是不一樣的,由於這種狀況 a 的修改並不會影響到 b, 它是由編譯器完成的,它有利於節省空間。而一個對象引用變量修改了這個對象的內部狀態,會影響到另外一個對象引用變量。 

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()方法才能保證每次都建立一個新的對象。 因爲 String 類的值不可變性(immutable) ,當 String 變量須要常常變換其值時,應該考慮使用 StringBuffer 或 StringBuilder 類,以提升程序效率。


轉載自:http://blog.sina.com.cn/s/blog_5da93c8f0101jkkc.htmlui

 

先解釋一下內存中的三個區:
JAVA的JVM的內存可分爲3個區:堆(heap)、棧(stack)和方法區(method)
堆區:
1.存儲的所有是對象,每一個對象都包含一個與之對應的class的信息。(class的目的是獲得操做指令)
2.jvm只有一個堆區(heap)被全部線程共享,堆中不存放基本類型和對象引用,只存放對象自己
棧區:
1.每一個線程包含一個棧區,棧中只保存基礎數據類型的對象和自定義對象的引用(不是對象),對象都存放在堆區中
2.每一個棧中的數據(原始類型和對象引用)都是私有的,其餘棧不能訪問。
3.棧分爲3個部分:基本類型變量區、執行環境上下文、操做指令區(存放操做指令)。
方法區:
1.又叫靜態區,跟堆同樣,被全部的線程共享。方法區包含全部的class和static變量。
2.方法區中包含的都是在整個程序中永遠惟一的元素,如class,static變量。 

方法區存放裝載的類數據信息包括: 
    (1):基本信息: 
           1)每一個類的全限定名 
           2)每一個類的直接超類的全限定名(可約束類型轉換) 
           3)該類是類仍是接口 
           4)該類型的訪問修飾符 
           5)直接超接口的全限定名的有序列表 
    (2):每一個已裝載類的詳細信息: 
           1)運行時常量池: 
              存放該類型所用的一切常量(直接常量和對其它類型、字段、方法的符 
            號引用),它們以數組形式經過索引被訪問,是外部調用與類聯繫及類型對 
            象化的橋樑。它是類文件(字節碼)常量池的運行時表示。(還有一種靜態常量池,在字節碼文件中)。 
           2)字段信息: 
              類中聲明的每個字段的信息(名,類型,修飾符)。 
           3)方法信息: 
              類中聲明的每個方法的信息(名,返回類型,參數類型,修飾符,方 
            法的字節碼和異常表)。 
           4)靜態變量 
           5)到類 classloader 的引用:即到該類的類裝載器的引用。 
           6)到類 class 的引用:  虛擬機爲每個被裝載的類型建立一個 class 實例, 用來表明這個被裝載的類
spa

相關文章
相關標籤/搜索