Java虛擬機器--堆的配置引數(四)
最大堆和初始堆的設定
說明:
- Java程序啟動時,虛擬機器就會分配一塊初始堆空間,可以使用引數-Xms指定這塊空間的大小;
- 如果初始堆空間耗盡,虛擬機器會對堆空間繼續擴充套件,其擴充套件上限為最大堆空間,最大堆空間可以使用引數-Xmx指定;
示例1:通過此例,說明最大堆,初始堆以及系統可用記憶體的含義和彼此之間的關係:
public class HeapAlloc { public static void main(String[] args) { //列印了基本的系統資訊,包括最大可用記憶體,當前空閒記憶體和當前總記憶體; System.out.println("maxMemory = "); System.out.println(Runtime.getRuntime().maxMemory() + "bytes"); System.out.println("free mem = "); System.out.println(Runtime.getRuntime().freeMemory() + "bytes"); System.out.println("total mem = "); System.out.println(Runtime.getRuntime().totalMemory() + "bytes"); //申請1MB記憶體空間,該記憶體分配在堆上 byte[] b = new byte[1*1024*1024]; System.out.println("分配了1M空間給陣列"); //列印最大可用記憶體,當前空閒記憶體和當前總記憶體; System.out.println("maxMemory = "); System.out.println(Runtime.getRuntime().maxMemory() + "bytes"); System.out.println("free mem = "); System.out.println(Runtime.getRuntime().freeMemory() + "bytes"); System.out.println("total mem = "); System.out.println(Runtime.getRuntime().totalMemory() + "bytes"); //申請4MB記憶體空間,該記憶體分配在堆上 b = new byte[4*1024*1024]; System.out.println("分配了4M空間給陣列"); System.out.println("maxMemory = "); System.out.println(Runtime.getRuntime().maxMemory() + "bytes"); System.out.println("free mem = "); System.out.println(Runtime.getRuntime().freeMemory() + "bytes"); System.out.println("total mem = "); System.out.println(Runtime.getRuntime().totalMemory() + "bytes"); } }
輸出效果:
說明:這裡的最大記憶體是指-Xmx的取值,當前總記憶體應該不小於-XMs的設定,因為當前總記憶體總是在-Xms和-Xmx之間,從-Xms開始根據需要向上增長;而當前空閒空間應該是當前總記憶體減去當前已經使用的空間;使用如下引數執行程式:-Xmx20m -Xms5m -XX:+PrintCommandLineFlags -XX:+PrintGCDetails -XX:+UseSerialGC輸出結果如下: -XX:InitialHeapSize=5242880 -XX:MaxHeapSize=20971520 -XX:+PrintCommandLineFlags -XX:+PrintGCDetails -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseSerialGC maxMemory = 20316160bytes free mem = 4466664bytes total mem = 5111808bytes [GC[DefNew: 630K->128K(1536K), 0.0059443 secs] 630K->463K(4992K), 0.0082716 secs] [Times: user=0.00 sys=0.02, real=0.01 secs] 分配了1M空間給陣列 maxMemory = 20316160bytes free mem = 3559728bytes total mem =5111808bytes [GC[DefNew: 1180K->0K(1536K), 0.0041030 secs][Tenured: 1487K->1487K(3456K), 0.0126827 secs] 1515K->1487K(4992K), [Perm : 2564K->2564K(21248K)], 0.0169347 secs] [Times: user=0.02 sys=0.00, real=0.02 secs] 分配了4M空間給陣列 maxMemory = 20316160bytes free mem = 3675952bytes total mem = 9441280bytes Heap def new generation total 1664K, used 77K [0x00000000f9a00000, 0x00000000f9bc0000, 0x00000000fa0a0000) eden space 1536K, 5% used [0x00000000f9a00000, 0x00000000f9a135b0, 0x00000000f9b80000) from space 128K, 0% used [0x00000000f9b80000, 0x00000000f9b80000, 0x00000000f9ba0000) to space 128K, 0% used [0x00000000f9ba0000, 0x00000000f9ba0000, 0x00000000f9bc0000) tenured generation total 7556K, used 5583K [0x00000000fa0a0000, 0x00000000fa801000, 0x00000000fae00000) the space 7556K, 73% used [0x00000000fa0a0000, 0x00000000fa613e68, 0x00000000fa614000, 0x00000000fa801000) compacting perm gen total 21248K, used 2570K [0x00000000fae00000, 0x00000000fc2c0000, 0x0000000100000000) the space 21248K, 12% used [0x00000000fae00000, 0x00000000fb082b88, 0x00000000fb082c00, 0x00000000fc2c0000) No shared spaces configured.
分析:
當前的最大記憶體由-XX:MaxHeapSize=20971520指定,它正好是20*1024*1024=20971520位元組。而列印的最大可用記憶體僅僅為20316160位元組,比設定值略少。這是因為分配給堆的記憶體空間和時間可用的記憶體空間並非一個概念。由於垃圾回收的需要,虛擬機器會堆堆空間進行分割槽管理,不同的區域採用不同的回收演算法,一些演算法會使用空間換時間的策略工作,因此會存在可用記憶體的損失。最終的結果就是實際可用記憶體會浪費大小等於from/to的空間;
提示:
在實際使用時,也可以直接將初始堆將初始值-Xms與最大堆-Xmx設定相等。這樣的好處時減少程式執行時進行的垃圾回收次數,從而提高效能;
新生代的配置
引數-Xmm:用於設定新生代的大小;設定一個較大的新生代會減小老年代的大小,這個引數對系統性能以及GC行為有很大的影響。新生代的大小一般設定為整個堆空間的1/3到1/4左右;
引數-XX:SurvivorRation:用來設定新生代中eden空間和from/to空間的比例關係,含義如下:
-XX:SurvivorRatio = eden/from=eden/to
實際工作的基本策略:儘可能將物件預留在新生代,減少老年代GC的次數;
引數-XX:NewRatio:設定新生代和老年代的比例,含義如下:
-XX:NewRatio=老年代/新生代
注意:-XX:SurvivorRation可以設定eden區與survivor區的比例;-XX:NewRatio可以設定老年代與新生代的比例圖解,幾個重要的堆分配引數的含義:
堆溢位處理
說明:Java程式執行時,如果堆空間不足,則有可能丟擲記憶體溢位錯誤(Out Of Memory)簡稱為OOM,出現此問題,系統會被迫退出,如下圖:
-XX:+HeapDumpOnOutOfMemoryError:該引數在記憶體溢位時匯出整個堆資訊;
-XX:HeapDumpPath:可以指定匯出堆的存放路徑;
示例1:測試兩個引數
public class DumpOOM {
public static void main(String[] args) {
Vector v = new Vector();
for (int i = 0; i < 25; i++) {
v.add(new byte[1*1024*1024]);
}
}
}
使用如下引數執行該程式:-Xmx20m -Xms5m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/a.dump分析:20MB堆空間不足以容納25MB記憶體,系統發生記憶體溢位,控制檯結果如下:
java.lang.OutOfMemoryError: Java heap space
Dumping heap to d:/a.dump ...
Heap dump file created [18971140 bytes in 0.067 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at hey.up2.DumpOOM.main(DumpOOM.java:23)
虛擬機器已將當前堆資訊匯出,儲存到d:/a.dump,可使用MAT工具開啟此檔案分析
示例2:除了發生OOM時匯出堆資訊,虛擬機器還允許在發生錯誤時執行一個指令碼檔案,該檔案可以用於崩潰程式的自救,報警或通知;
1.準備printstack.bat指令碼:
D:/tools/jdk1.7_40/bin/jstack-F %1 > D:/a.txt
2.該指令碼將會匯出給定Java虛擬機器程序的執行緒資訊,並儲存在D:/a.txt檔案中
3.使用如下引數執行上述程式碼:
-Xmx20m -Xms5m"-XX:OnOutOfMemoryError=D:/tools/jdk1.7_40/bin/printstack.bat %p"-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/a.dump
4.在程式異常退出時,系統D盤會生成新檔案a.txt,裡面儲存著執行緒轉存資訊。本例中,D:/tools/jdk1.7_40為JAVA_HOME目錄相關推薦
《自己動手寫java虛擬機器》學習筆記(四)-----搜尋class檔案(java)
專案地址:https://github.com/gongxianshengjiadexiaohuihui 首先是定義一個抽象類,把四種路徑的格式抽象出來 Entry.java package classpath; import java.io.IOException;
Java虛擬機器--堆的配置引數(四)
最大堆和初始堆的設定 說明: Java程序啟動時,虛擬機器就會分配一塊初始堆空間,可以使用引數-Xms指定這塊空間的大小;如果初始堆空間耗盡,虛擬機器會對堆空間繼續擴充套件,其擴充套件上限為最大堆空間,最大堆空間可以使用引數-Xmx指定;示例1:通過此例,說明最大堆,初始堆
【Java】「深入理解Java虛擬機器」學習筆記(1) - Java語言發展趨勢
這本書寫的比較早,現在這些功能都已經不同程度的實現了。 1、模組化 JDK9之前的版本都是一個整體,使用者可能只需要使用一個小功能,但他不得不下載整個JDK。不能滿足定製化需求,顯然Java語言的發展因此大大受限。 所以,Sun公司在OpenJDK建立了一個Jigsaw(拼圖)的專案來推動模
【Java】「深入理解Java虛擬機器」學習筆記(2)-記憶體管理
一、執行時資料區 JVM在執行Java程式的時候,將其執行時資料區劃分為若干不同區域。它們的用途和建立及銷燬的時間不同。 1、程式計數器(Program Counter Register) 是一塊很小的記憶體空間。當執行緒執行的是Java方法,它記錄的是當前正在執行的
《深入理解java虛擬機器》 精華總結(面試)
文章目錄 一、執行時資料區域 1.1 程式計數器 1.2 Java虛擬機器棧 1.3 本地方法棧 1.4 Java堆 1.5 方法區 1.6 執行時常量池 二、hotspot虛擬機器物件
《深入理解java虛擬機器》讀書筆記(三)---- 垃圾回收演算法及垃圾收集器介紹
一、垃圾回收演算法 1、標記--清除演算法 標記--清除(Mark-Sweep)演算法,分為標記和清除兩個階段,首先標記出所有需要回收的物件,在標記完成後統一回收所有被標記的物件,這是最基礎的收集演算法,後續很多演算法都是基於這種思想進行設計的。 標記--清除演算法主要的不足有兩點:一個
《深入理解java虛擬機器》讀書筆記(二)---- Java記憶體區域與記憶體溢位異常
執行時資料區域 java虛擬機器所管理的記憶體將會包括以下幾個執行時資料區域: 1、程式計數器 程式計數器是一塊較小的記憶體空間,它可以看作是當前執行緒所執行位元組碼的行號指示器。在虛擬機器的概念模型裡,位元組碼直譯器的工作就是通過改變這個計數器的值來選取下一條需要執
《深入理解java虛擬機器》讀書筆記(一)---- 類載入機制
類載入的時機 1、類從虛擬機器載入到記憶體開始,到卸載出記憶體為止,整個生命週期分為七個階段:載入、驗證、準備、解析、初始化、使用和解除安裝。其中驗證、準備和解析統稱為連線階段。 2、載入、驗證、準備、初始化和解除安裝這五個階段是按順序執行的,而解析階段卻不一定,解析可以在初始化之後
《自己動手寫java虛擬機器》學習筆記(六)-----解析class檔案(java)
專案地址:https://github.com/gongxianshengjiadexiaohuihui 註釋都寫的很清楚,有一些概念問題,請參考go版本的實現 目錄結構 首先是位元組轉換工具,因為java和go的類庫不同,另外需注意class檔案是大端儲存方式(高位元組放低地址,
《自己動手寫java虛擬機器》學習筆記(五)-----解析class檔案(go)
專案地址:https://github.com/gongxianshengjiadexiaohuihui 上一節,我們已經通過路徑找到了指定的class檔案,這一節,我們開始解析class檔案,我們知道class檔
《自己動手寫java虛擬機器》學習筆記(三)-----搜尋class檔案(go)
專案地址:https://github.com/gongxianshengjiadexiaohuihui 我們都知道,.java檔案編譯後會形成.class檔案,然後class檔案會被載入到虛擬機器中,被我們使用,那麼虛擬機器如何從那裡尋找這些class檔案呢,jav
《自己動手寫java虛擬機器》學習筆記(二)-----命令列工具(java)
專案地址:https://github.com/gongxianshengjiadexiaohuihui 首先是Cmd的類 /** * @ClassName Cmd * @Description TODO * @Author Mr.G * @Date 2018/10/9 9:40
《自己動手寫java虛擬機器》學習筆記(一)-----命令列工具(go)
專案地址:https://github.com/gongxianshengjiadexiaohuihui 在今年三月份的時候,看過這本書,但是可能知識儲備不足,許多東西都一知半解,導致看到一半就看不下去了,現在覺得自己進步挺大的,決定重新拾起這本書,並且把
《自己動手寫java虛擬機器》學習筆記(七)-----執行緒私有執行時資料區(go)
專案地址:https://github.com/gongxianshengjiadexiaohuihui 在執行java程式時,Java虛擬機器需要使用記憶體來存放各種各樣的資料,Java虛擬機器規範把這些記憶體的區
關於Java虛擬機器二三事(八)---JVM機器指令集及其執行引擎
1.前言 Java虛擬機器和真實的計算機一樣,執行的都是二進位制的機器碼;而我們將.java原始碼編譯成.class檔案,class檔案便是Java虛擬機器能夠認識的二進位制機器碼。Java能夠識別class檔案中的資訊和機器指令,進而執行這些機器指令。那麼,Java虛
java虛擬機器結構詳解(JVM)
廢話不多說,先直接上個圖: 上圖為JVM整體組成結構,有幾個模組組成: 1.class檔案生成模組: 通過jdk自帶的javac編譯命令生成 中間過程就是javac編譯程式內部處理的過程,核心就是針對原始碼詞法和語法的分析。 2.類載入器子系統模組: JVM執行時
關於Java虛擬機器二三事(五)---類檔案結構(上)
1.前言 當編寫完一段Java程式碼並儲存以後,其實Java程式碼會儲存在以.Java為副檔名作為結尾的檔案中,如test.java,而這個檔案若想在JVM上執行,則必須先利用javac編譯器進行編寫,形成所謂的“位元組碼(ByteCode)檔案”,即接下來要分析的重點
Java虛擬機器面試題精選(二)
概述現在面試Java開發時,基本都會問到Java虛擬機器的知識,根據職位不同問的內容深淺又有所區別。本文整理了10道面試中常問的Java虛擬機器面試題,希望對正在面試的同學有所幫助。11.介紹下垃圾收集
java虛擬機器記憶體管理機制(一):JVM記憶體管理總結【分享】
近期看了看Java記憶體洩露的一些案例,跟原來的幾個哥們討論了一下,深入研究發現JVM裡面還是有不少以前不知道的細節,這裡稍微剖析一下。先看一看JVM的內部結構——如圖所示,JVM主要包括兩個子系統和兩個元件。兩個子系統分別是Class loader子系統和Execution
《自己動手寫Java虛擬機器》學習筆記(五)指令集和直譯器
第五章 指令集和直譯器 本章基於第三章(解析.class檔案)和第四章(執行時資料區),編寫一個建議的直譯器。 5.1 位元組碼和指令集 每一個類或者介面都可以被Java編譯器編譯成為一個.class檔案,類或介面的方法資訊就放在.class檔案的method_info