JVM的內存區域的溢出

棧溢出

每一個線程都擁有本身的棧,當前執行的方法在棧的頂部,每次方法調用時,一個新的棧幀建立並壓到棧頂。當方法正常返回或拋出未捕獲的異常時,棧幀就會出站。java

棧能夠是動態分配也能夠固定大小。若是線程請求一個超過容許範圍的空間,就會拋出一個StackOverflowError。若是線程須要一個新的棧幀,可是沒有足夠的內存能夠分配,就會拋出一個 OutOfMemoryError。算法

棧溢出的場景

/**

* @author LXA

* 棧溢出

*/

public class Stack

{

    public static void main(String[] args)

    {

        new Stack().test();

    }

    public void test()

    {

        test();

    }

}

報錯:緩存

java.lang.StackOverflowError

分析

當前調用的方法會在棧中建立棧幀,方法陷入死循環中,就會不停的在棧中建立對象,而不會銷燬棧幀,直到棧沒有空間時,就會溢出。函數

堆溢出:

類被初始化是,new出的對象,被分配在堆上,對象不停的建立,並且不被釋放,在垃圾回收機制中,佔滿青年代,將會被移到老年代中,當老年代中的空間不夠時,就會oom。spa

堆溢出的示例

/**

* @author LXA

* 堆溢出

*/

public class Heap

{

    public static void main(String[] args)

    {

        ArrayList list=new ArrayList();

        while(true)

        {

            list.add(new Heap());

        }

    }

}

報錯:線程

報錯:

java.lang.OutOfMemoryError: Java heap space

堆上的垃圾回收算法

基於 標記清除算法進行的。 新生代收集器使用的收集器:Serial、PraNew、Parallel Scavenge 老年代收集器使用的收集器:Serial Old、Parallel Old、CMS指針

4、GC的執行機制code

因爲對象進行了分代處理,所以垃圾回收區域、時間也不同。GC有兩種類型:Scavenge GC和Full GC。對象

Scavenge GC接口

通常狀況下,當新對象生成,而且在Eden申請空間失敗時,就會觸發Scavenge GC,對Eden區域進行GC,清除非存活對象,而且把尚且存活的對象移動到Survivor區。而後整理Survivor的兩個區。這種方式的GC是對年輕代的Eden區進行,不會影響到年老代。由於大部分對象都是從Eden區開始的,同時Eden區不會分配的很大,因此Eden區的GC會頻繁進行。於是,通常在這裏須要使用速度快、效率高的算法,使Eden去能儘快空閒出來。

Full GC

對整個堆進行整理,包括Young、Tenured和Perm。Full GC由於須要對整個堆進行回收,因此比Scavenge GC要慢,所以應該儘量減小Full GC的次數。在對JVM調優的過程當中,很大一部分工做就是對於FullGC的調節。有以下緣由可能致使Full GC:

1.年老代(Tenured)被寫滿

2.持久代(Perm)被寫滿

3.System.gc()被顯示調用

4.上一次GC以後Heap的各域分配策略動態變化

Java內存泄露

通常來講內存泄漏有兩種狀況。一種狀況如在C/C++ 語言中的,在堆中的分配的內存,在沒有將其釋放掉的時候,就將全部能訪問這塊內存的方式都刪掉(如指針從新賦值);另外一種狀況則是在內存對象明明已經不須要的時候,還仍然保留着這塊內存和它的訪問方式(引用)。第一種狀況,在 Java 中已經因爲垃圾回收機制的引入,獲得了很好的解決。因此, Java 中的內存泄漏,主要指的是第二種狀況。

Vector v = new  Vector( 10 );  
 for  ( int  i = 1 ;i < 100 ; i ++ ){  
 Object o = new  Object();  
 v.add(o);  
 o = null ;  
 }

在這個例子中,代碼棧中存在Vector 對象的引用 v 和 Object 對象的引用 o 。在 For 循環中,咱們不斷的生成新的對象,而後將其添加到 Vector 對象中,以後將 o 引用置空。問題是當 o 引用被置空後,若是發生 GC ,咱們建立的 Object 對象是否可以被 GC 回收呢?答案是否認的。由於, GC 在跟蹤代碼棧中的引用時,會發現 v 引用,而繼續往下跟蹤,就會發現 v 引用指向的內存空間中又存在指向 Object 對象的引用。也就是說盡管 o 引用已經被置空,可是 Object 對象仍然存在其餘的引用,是能夠被訪問到的,因此 GC 沒法將其釋放掉。若是在此循環以後, Object 對象對程序已經沒有任何做用,那麼咱們就認爲此 Java 程序發生了內存泄漏。

持久代:

用於存放靜態文件,現在Java類、方法等。持久代對垃圾回收沒有顯著影響,可是有些應 用可能動態生成或者調用一些class,例如Hibernate 等,在這種時候須要設置一個比較大的持 久代空間來存放這些運行過程當中新增的類。持久代大小經過-XX:MaxPermSize=<N>進行設置。

持久帶補充:持久帶也稱爲方法區 方法區:方法區存儲每個java類的結構信息:好比運行時常量池,字段和方法數據,構造函數和普通方法的字節碼內容以及類、實例、接口初始化時須要使用到的特殊方法等數據。 方法區也被稱爲永久代,若是不顯示指定的話,GC回收的目標僅針對方法區的常量池和類型卸載

非堆內存的溢出

非堆內存包括: 永久代,包括: 方法區 駐留字符串(interned strings) 代碼緩存(Code Cache):用於編譯和存儲那些被 JIT 編譯器編譯成原生代碼的方法。

加載的類過多時,就會溢出

相關文章
相關標籤/搜索