1. 程式人生 > 實用技巧 >記憶體結構篇:堆

記憶體結構篇:堆

一、定義

Java 堆(Heap)(執行緒共享

  • 所有執行緒共享的一塊記憶體區域,在虛擬機器啟動時建立。
  • 此記憶體區域的唯一目的就是存放物件例項,“幾乎”所有的物件例項都在這裡分配記憶體用new建立的類變數才是例項

特點:

  • 它是執行緒共享的,堆中物件都需要考慮執行緒安全的問題
  • 有垃圾回收機制,是垃圾回收的主要區域(“GC堆”)(Garbage Collected Heap)
  • 現代的垃圾收集器基本都是採用分代收集演算法,其主要的思想是針對不同型別的物件採用不同的垃圾回收演算法。可以將堆分成兩塊:
    • 新生代(Young Generation)
    • 老年代(Old Generation)
  • 不需要連續記憶體,並且可以動態增加其記憶體,增加失敗會丟擲 OutOfMemoryError 異常(但對於大物件如陣列物件,多數虛擬機器實現出於實現簡單、儲存高效的考慮,很可能會要求連續的記憶體空間)

可以通過 -Xms 和 -Xmx 這兩個虛擬機器引數來指定一個程式的堆記憶體大小,第一個引數設定初始值,第二個引數設定最大值

java -Xms1M -Xmx2M HackTheJava

二、堆記憶體溢位

物件例項一直被使用,同時一直增加對堆記憶體的佔用,導致堆記憶體無法釋放,出現 OutOfMemoryError 異常

/**
 * 演示堆記憶體溢位 java.lang.OutOfMemoryError: Java heap space
 * -Xmx8m
 */
public class Demo1_5 {

    public static void main(String[] args) {
        int i = 0;
        try {
            List<String> list = new ArrayList<>();
            String a = "hello";
            while (true) {
                list.add(a); // hello, hellohello, hellohellohellohello ...
                a = a + a;  // hellohellohellohello
                i++;
            }
        } catch (Throwable e) {
            e.printStackTrace();
            System.out.println(i);
        }
    }
}

報錯資訊:

24
java.lang.OutOfMemoryError: Java heap space
	at java.util.Arrays.copyOf(Arrays.java:3332)
	at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:124)
	at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:448)
	at java.lang.StringBuilder.append(StringBuilder.java:136)
	at cn.itcast.jvm.t1.heap.Demo1_5.main(Demo1_5.java:19)

三、堆記憶體診斷

  1. jps 工具
  • 檢視當前系統中有哪些 java 程序
  1. jmap 工具
  • 檢視堆記憶體佔用情況 jmap - heap 程序id
  1. jconsole 工具
  • 圖形介面的,多功能的監測工具,可以連續監測
  1. jvisualvm 工具
    • 圖形介面,和 jconsole 類似,可以使用堆 Dump ,檢視物件個數等資訊

案例:

  • 垃圾回收後,記憶體佔用仍然很高
/**
 * 演示檢視物件個數 堆轉儲 dump
 */
public class Demo1_13 {

    public static void main(String[] args) throws InterruptedException {
        List<Student> students = new ArrayList<>();
        for (int i = 0; i < 200; i++) {
            students.add(new Student());
//            Student student = new Student();
        }
        Thread.sleep(1000000000L);
    }
}
class Student {
    private byte[] big = new byte[1024*1024];
}