《深入理解java虛擬機器》學習筆記2——Java記憶體溢位例項
通過簡單的小例子程式,演示java虛擬機器各部分記憶體溢位情況:
(1).java堆溢位:
Java堆用於儲存例項物件,只要不斷建立物件,並且保證GC Roots到物件之間有引用的可達,避免垃圾收集器回收例項物件,就會在物件數量達到堆最大容量時產生OutOfMemoryError異常。
想要方便快速地產生堆溢位,要使用如下java虛擬機器引數:-Xms10m(最小堆記憶體為10MB),-Xmx10m(最大堆記憶體為10MB,最小堆記憶體和最大堆記憶體相同是為了避免堆動態擴充套件),-XX:+HeapDumpOnOutOfMemoryError可以讓java虛擬機器在出現記憶體溢位時產生當前堆記憶體快照以便進行異常分析。
例子程式碼如下:
- public class HeapOOM{
- static class OOMObject{
- }
- public static void main(String[] args){
- List<OOMObject> list = new ArrayList<OOMObject>();
- while(true){
- list.add(new OOMObject());
- }
- }
- }
執行一段時間就會發現產生OutOfMemoryError異常,並且產生了堆記憶體異常dump檔案。
(2).java虛擬機器棧和本地方法棧溢位:
由於Sun的HotSpot虛擬機器不區分java虛擬機器棧和本地方法棧,因此對於HotSpot虛擬機器來說-Xoss引數(設定本地方法棧大小)雖然存在,但是實際上是無效的,棧容量只能由-Xss引數設定。
由於Java虛擬機器棧會出現StackOverflowError和OutOfMemoryError兩種異常,所以分別使用兩個例子演示這兩種情況:
a.java虛擬機器棧深度溢位:
單執行緒的環境下,無論是由於棧幀太大,還是虛擬機器棧容量太小,當記憶體無法再分配的時候,虛擬機器總丟擲StackOverflowError異常。使用-Xss128k將java虛擬機器棧大小設定為128kb,例子程式碼如下:
- public class JavaVMStackOF{
- private int stackLength = 1;
- public void stackLeak(){
- statckLength++;
- stackLeak();
- }
- public static void main(String[] args){
- JavaVMStackOF oom = new JavaVMStackOF();
- oom.stackLeak();
- }
- }
執行一段時間後,產生StackOverflowError異常。Java虛擬機器棧溢位一般會產生在方法遞迴呼叫過多而java虛擬機器棧記憶體不夠的情況下。
b.java虛擬機器棧記憶體溢位:
多執行緒環境下,能夠建立的執行緒最大記憶體=實體記憶體-最大堆記憶體-最大方法區記憶體,在java虛擬機器棧記憶體一定的情況下,單個執行緒佔用的記憶體越大,所能建立的執行緒數目越小,所以在多執行緒條件下很容易產生java虛擬機器棧記憶體溢位的異常。
使用-Xss2m引數設定java虛擬機器棧記憶體大小為2MB,例子程式碼如下:
- public class JavaVMStackOOM{
- private void dontStop(){
- while(true){
- }
- }
- public void stackLeakByThread{
- while(true){
- Thread t = new Thread(new Runnable(){
- public void run(){
- dontStop();
- }
- });
- t.start();
- }
- }
- public static void main(String[] args){
- JavaVMStackOOM oom = new JavaVMStackOOM();
- oom. stackLeakByThread();.
- }
- }
執行一段時間之後,java虛擬機器棧就會因為記憶體太小無法建立執行緒而產生OutOfMemoryError。
(3).執行時常量池溢位:
執行時常量池屬於方法區的一部分,可以使用-XX:PermSize=10m和-XX:MaxPermSize=10m將永久代最大記憶體和最小記憶體設定為10MB大小,並且由於永久代最大記憶體和最小記憶體大小相同,因此無法擴充套件。
String的intern()方法用於檢查常量池中如果有等於此String物件的字串存在,則直接返回常量池中的字串物件,否則,將此String物件所包含的字串新增到執行時常量池中,並返回此String物件的引用。因此String的intern()方法特別適合演示執行時常量池溢位,例子程式碼如下:
- public class RuntimeConstantPoolOOM{
- public static void main(String[] args){
- List<String> list = new ArrayList<String>();
- int i = 0;
- while(true){
- list.add(String.valueOf(i++).intern());
- }
- }
- }
執行一段時間,永久代記憶體不夠,執行時常量池因無法再新增常量而產生OutOfMemoryError。
(4).方法區溢位:
執行時常量池是方法區的一部分,他們都屬於HotSpot虛擬機器中的永久代記憶體區域。方法區用於存放Class的相關資訊,Java的反射和動態代理可以動態產生Class,另外第三方的CGLIB可以直接操作位元組碼,也可以動態產生Class,實驗通過CGLIB來演示,同樣使用-XX:PermSize=10m和-XX:MaxPermSize=10m將永久代最大記憶體和最小記憶體設定為10MB大小,並且由於永久代最大記憶體和最小記憶體大小相同,因此無法擴充套件。例子程式碼如下:
- public class JavaMethodAreaOOM{
- public static void main(String[] args){
- while(true){
- Enhancer enhancer = new Enhancer();
- enhancer.setSuperClass(OOMObject.class);
- enhancer.setUseCache(false);
- enhancer.setCallback(new MethodInterceptor(){
- public Object intercept(Object obj, Method method, Object[] args,
- MethodProxy proxy)throws Throwable{
- return proxy.invokeSuper(obj, args);
- }
- });
- enhancer.create();
- }
- }
- class OOMObject{
- }
- }
執行一段時間之後,永久代記憶體不夠,方法區無法再存放CGLIB建立處理的Class資訊,產生方法區OutOfMemoryError。
(5).本機直接記憶體溢位:
Java虛擬機器可以通過引數-XX:MaxDirectMemorySize設定本機直接記憶體可用大小,如果不指定,則預設與java堆記憶體大小相同。JDK中可以通過反射獲取Unsafe類(Unsafe的getUnsafe()方法只有啟動類載入器Bootstrap才能返回例項)直接操作本機直接記憶體。通過使用-XX:MaxDirectMemorySize=10M,限制最大可使用的本機直接記憶體大小為10MB,例子程式碼如下:
- public class DirectMemoryOOM{
- private static final int _1MB = 1024* 1024 * 1024;
- publc static void main(String[] args) throws Exception{
- Field unsafeField = Unsafe.class.getDeclaredFields()[0];
- unsafeField.setAccessible(true);
- Unsafe unsafe = (Unsafe) unsafeField.get(null);
- while(true){
- //unsafe直接想作業系統申請記憶體
- unsafe.allocateMemory(_1MB);
- }
- }
- }
當執行一段時間之後,10MB的本機直接記憶體被分配光,無法在進行直接記憶體分配時,產生OutOfMemoryError。
相關文章
- 深入理解Java虛擬機器-Java記憶體區域與記憶體溢位異常Java虛擬機記憶體溢位
- Java虛擬機器記憶體模型學習筆記Java虛擬機記憶體模型筆記
- 深入理解JVM虛擬機器-JVM記憶體區域與記憶體溢位JVM虛擬機記憶體溢位
- 深入理解Java虛擬機器筆記-自動記憶體管理機制Java虛擬機筆記記憶體
- Java虛擬機器01——Java記憶體資料區域和記憶體溢位異常Java虛擬機記憶體溢位
- Java8虛擬機器(JVM)記憶體溢位實戰Java虛擬機JVM記憶體溢位
- 《深入java虛擬機器》讀書筆記之Java記憶體區域Java虛擬機筆記記憶體
- 《深入理解 Java 虛擬機器》筆記整理Java虛擬機筆記
- 深入理解虛擬機器之Java記憶體區域虛擬機Java記憶體
- 深入理解Java虛擬機器筆記之六記憶體分配與回收策略Java虛擬機筆記記憶體
- JAVA虛擬機器學習筆記Java虛擬機機器學習筆記
- 深入理解 Java 虛擬機器:Java 記憶體區域透徹分析Java虛擬機記憶體
- 深入理解Java虛擬機器-Java記憶體區域透徹分析Java虛擬機記憶體
- 深入理解Java虛擬機器 --- 記憶體分配與回收策略Java虛擬機記憶體
- 《深入理解Java虛擬機器》個人筆記Java虛擬機筆記
- 深入理解Java虛擬機器(自動記憶體管理機制)Java虛擬機記憶體
- 深入學習Java虛擬機器——垃圾收集器與記憶體分配策略Java虛擬機記憶體
- 深入理解Java虛擬機器之JVM記憶體佈局篇Java虛擬機JVM記憶體
- 深入理解java虛擬機器——讀書筆記1Java虛擬機筆記
- Java記憶體溢位Java記憶體溢位
- 《深入理解Java虛擬機器》(二)--垃圾收集器與記憶體分配策略(2)Java虛擬機記憶體
- Java棧溢位|記憶體洩漏|記憶體溢位Java記憶體溢位
- 對jvm虛擬機器 記憶體溢位的思考JVM虛擬機記憶體溢位
- JAVA 虛擬機器可用記憶體Java虛擬機記憶體
- 深入理解JAVA虛擬機器學習筆記18——位元組碼指令2(運算指令)Java虛擬機機器學習筆記
- 深入理解Java虛擬機器-垃圾收集器與記憶體分配策略Java虛擬機記憶體
- 深入理解Java虛擬機器 - 垃圾收集器與記憶體分配策略Java虛擬機記憶體
- 《深入理解java虛擬機器》第3版筆記3Java虛擬機筆記
- 深入理解Java虛擬機器筆記1: OOM實戰Java虛擬機筆記OOM
- 【Java 虛擬機器筆記】記憶體分配策略相關整理Java虛擬機筆記記憶體
- 用例項帶你深入理解Java記憶體模型Java記憶體模型
- 《深入java虛擬機器》讀書筆記之垃圾收集器與記憶體分配策略Java虛擬機筆記記憶體
- Java 虛擬機器之三:Java虛擬機器的記憶體結構Java虛擬機記憶體
- 深入理解Java虛擬機器筆記之二關於物件Java虛擬機筆記物件
- Java零基礎學習之路(九)Java虛擬機器記憶體管理Java虛擬機記憶體
- 【記憶體洩漏和記憶體溢位】JavaScript之深入淺出理解記憶體洩漏和記憶體溢位記憶體溢位JavaScript
- 深入理解JVM虛擬機器11:Java記憶體異常原理與實踐JVM虛擬機Java記憶體
- 深入理解Java虛擬機器之物件的記憶體佈局、訪問定位Java虛擬機物件記憶體
- Java虛擬機器之記憶體區域Java虛擬機記憶體