【3】JVM-OutOfMemory異常重現

? JVM中常見的OOM,那么如何通過自己編寫代碼產生這些OOM異常呢?通過寫代碼重現異常,是為了避免在工作中寫出有OOM BUG的代碼。之前雖然看過相關文章,但是沒自己寫過這些代碼,這次在編寫的實際過程中,由于和書本使用的JDK版本不一致,也會有點問題。其中印象最深刻的就是從JDK1.7開始常量池就已經不放在方法區了,而是改到了Java堆中,所以《深入理解JAVA虛擬機》中的有些知識也需要更新了。下面的代碼基于JDK1.7來的。并且在運行程序的時候需要設置JVM參數,如果不設置,輕則需要等待很長時間才會出現異常,重則系統假死甚至導致系統內存溢出。

? ? 在測試直接內存的時候,引用了rt.jar中的sun.misc.Unsafe類,如果使用了Eclipse作為IDE,需要修改windows-->preferences-->java-->compiler-->Errors/Warinings,選擇Deprecated and restricted API,將Forbidden reference(access rules)修改成ignore。

  1 package org.zsl.learn.oom;
  2 
  3 import java.lang.reflect.Field;
  4 import java.lang.reflect.Method;
  5 import java.util.ArrayList;
  6 import java.util.List;
  7 
  8 
  9 import net.sf.cglib.proxy.Enhancer;
 10 import net.sf.cglib.proxy.MethodInterceptor;
 11 import net.sf.cglib.proxy.MethodProxy;
 12 import sun.misc.Unsafe;
 13 
 14 /**
 15  * 測試在代碼中如何產生堆內存溢出、棧溢出(超出長度)、棧內存溢出(棧不能擴展的情況下OOM)、方法區內存溢出、常量池內存溢出
 16  * JDK1.7
 17  * @author Administrator
 18  *
 19  */
 20 public class TestOOM {
 21     private static int count = 1;
 22     private static final int _1MB = 1024*1024;
 23     
 24     List<String> list = new ArrayList<String>();
 25     
 26     //一個普通的對象
 27     static class OOMObjectClass{
 28         public OOMObjectClass(){}
 29     }
 30     
 31     /**
 32      * 通過list對象保持對對象列表的引用,不然GC收集對象,然后不斷地向列表中添加新的對象,就會發生OOM
 33      * 
 34      * @VM args:-verbose:gc -Xms10M -Xmx10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+HeapDumpOnOutOfMemoryError
 35      */
 36     public void testHeapOOM(){
 37         List<OOMObjectClass> list = new ArrayList<>();
 38         while(true){
 39             list.add(new OOMObjectClass());
 40         }
 41     }
 42     
 43     /**
 44      * 通過遞歸調用方法,從而讓方法棧產生棧 StackOverflowError
 45      * 
 46      * @VM args:-verbose:gc -Xss128k
 47      */
 48     public void stackLeak(){
 49         count++;
 50         stackLeak();
 51     }
 52     
 53     
 54     /**
 55      * 除了上述的遞歸調用可以產生溢出外,還有就是過多的線程,當棧內存無法動彈擴展是,會出現OOM
 56      * 
 57      * 由于在Window的JVM中,Jave的線程是映射到了操作系統的內核線程上,故而這段代碼的運行時非常危險的
 58      * 筆者運行的時候限制了JVM內存大小,但是棧內存可以動態擴展,所以電腦內存直接到了90%以上,我果斷停止了程序的運行
 59      * 由于棧內存只由-Xss參數控制,并沒有辦法讓其不自動擴展,所以這段代碼非常危險
 60      * 參數:-verbose:gc -Xms10M -Xmx10M -Xss2M
 61      */
 62     public void stackLeakByThread(){
 63         while(true){
 64             Thread t = new Thread(new Runnable() {
 65                 
 66                 @Override
 67                 public void run() {
 68                     while (true){
 69                         
 70                     }
 71                 }
 72             });
 73             t.start();
 74             count++;
 75         }
 76     }
 77     
 78     /**
 79      * 常量池是存在于方法區內的,故而只要限制了方法區的大小,當不斷新增常量的時候就會發生常量池的溢出
 80      * 
 81      * 筆者使用的是JDK1.7 64位,此時的常量池已經不存在與方法區中,而是遷移到了堆中,故而測試的時候需要限制JVM的堆大小,且不能自動擴展
 82      * @VM args: -Xms10M -Xmx10M
 83      */
 84     public void constantPoolOOM(){
 85         int i=0;
 86         while(true){
 87             list.add(String.valueOf(i++).intern()); //String類型的intern方法是將字符串的值放到常量池中
 88         }
 89     }
 90     
 91     /**
 92      * 方法區是存放一些類的信息等,所以我們可以使用類加載無限循環加載class,這樣就會出現方法區的OOM異常
 93      * 主要,使用內部類的時候,需要要使用靜態內部類,如果使用的是非靜態內部類,將不會發生方法區OOM
 94      * 使用了CGLib直接操作字節碼運行時,生成了大量的動態類
 95      * 需要者兩個jar包:cglib-2.2.2.jar   asm-3.1.jar
 96      * @VM args:-XX:PermSize=10M -XX:MaxPermSize=10M
 97      */
 98     public void methodAreaOOM(){
 99         while(true){
100             Enhancer eh = new Enhancer();
101             eh.setSuperclass(OOMObjectClass.class);
102             eh.setUseCache(false);
103             eh.setCallback(new MethodInterceptor() {
104                 @Override
105                 public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
106                     return arg3.invokeSuper(arg0, arg2);
107                 }
108             });
109             eh.create();
110         }
111     }
112     
113     /**
114      * 要討論這部分的內存溢出,首先必須要說一下什么是直接內存:
115      *     直接內存并不是JVM運行時數據區的一部分,也不是JVM規范中定義的內存區域,但是這部分內存也被頻繁的使用,也會產生OOM。
116      *     JDK1.4中新加入了NIO類,引入了一種Channel與Buffer的I/O方式,它可以使用Native函數庫直接分配堆外內存,然后通過一個存儲在JAVA堆里面的DirectByteBuffer對象作為
117      *     這些堆外內存的引用進而操作,這樣在某些場景中可以顯著的提高性能,避免了在native堆和java堆中來回復制數據。這這部分堆外內存就是直接內存了。
118      * 
119      * 直接內存雖然不會受到JAVA堆大小的限制,但是還是會受到本機內存大小的限制,故而服務器管理員在設置JVM內存管理參數的時候,如果忘記了直接內存,那么當程序進行動態擴展的時候,就有可能發生OOM
120      * 直接內存的容量可以通過-XX:MaxDirectMemorySize指定,如果不指定,那么默認與JAVA堆得最大值一樣。
121      * 
122      * @VM args:-Xmx20M -XX:MaxDirectMemorySize=10M
123      * @throws SecurityException 
124      * @throws NoSuchFieldException 
125      * @throws IllegalAccessException 
126      * @throws IllegalArgumentException 
127      */
128     public void directMemoryOOM() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException{
129         Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
130         unsafeField.setAccessible(true);
131         Unsafe unsafe = (Unsafe)unsafeField.get(null);
132         while(true){
133             unsafe.allocateMemory(_1MB);
134         }
135     }
136     
137     
138     
139     
140     public static void main(String[] args) {
141         TestOOM oom = new TestOOM();
142 //        ---------測試堆內存溢出-----------
143 //        oom.testHeapOOM();    
144         
145 //        ---------測試棧溢出----------
146 //        try{
147 //            oom.stackLeak(); 
148 //        }catch(Throwable error){
149 //            System.out.println("Stack length-->"+count);
150 //            throw error;
151 //        }
152         
153 //        ---------測試由于棧動態擴展導致的OOM----------        
154 //        try{
155 //            oom.stackLeakByThread();
156 //        }catch(Throwable error){
157 //            System.out.println("Stack length-->"+count);
158 //            throw error;
159 //        }
160         
161 //        ----------測試方法區溢出----------
162 //        oom.methodAreaOOM();
163         
164 //        ----------測試常量池溢出----------
165 //        oom.constantPoolOOM();
166         
167 //        ----------測試直接內存溢出----------
168         
169         try {
170             oom.directMemoryOOM();
171         } catch (Exception e) {
172             System.out.println(e);
173         }
174         
175         
176         
177     }
178     
179     
180 }

?

轉載于:https://www.cnblogs.com/printN/p/6901668.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/370574.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/370574.shtml
英文地址,請注明出處:http://en.pswp.cn/news/370574.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

CachedIntrospectionResults 初始化

轉載于:https://www.cnblogs.com/xiluhua/p/7862985.html

為什么有些內聯(行內)元素可以設置寬高?

為什么有些內聯&#xff08;行內&#xff09;元素如img、input可以設置寬高&#xff1f; 在說明之前我們先來了解一些定義。 塊級元素和內聯元素&#xff1a; ①塊級元素總是獨占一行&#xff0c;表現為另起一行開始&#xff0c;而且其后的元素也必須另起一行顯示。 寬度(w…

mongo數據庫和mysql數據庫的區別_Mongodb與mysql數據庫的區別

MySQLMongoDB說明mysqldmongod服務器守護進程mysqlmongo客戶端工具mysqldumpmongodump邏輯備份工具mysqlmongorestore邏輯恢復工具db.repairDatabase()修復數據庫mysqldumpmongoexport數據導出工具sourcemongoimport數據導入工具grant * privileges on *.* to …Db.addUser()Db…

在Eclipse中高效運行HTTP / REST集成測試

最近&#xff0c;我有機會使用由我親愛的Holger Staudacher編寫的OSGi-JAX-RS-Connector庫。 通過連接器&#xff0c;您可以通過將Path注釋的類型注冊為OSGi服務來輕松發布資源-實際上&#xff0c;它工作得很好。 對于我來說&#xff0c;使用普通的JUnit測試編寫驅動的服務類測…

Eclipse安裝TestNG插件

Eclipse安裝TestNG插件 TestNG是什么? TestNG按照其文檔的定義是&#xff1a; TestNG是一個測試框架&#xff0c;其靈感來自JUnit和NUnit的&#xff0c;但引入了一些新的功能&#xff0c;使其功能更強大&#xff0c;使用更方便。 TestNG是一個開源自動化測試框架;TestNG表示下…

basicdatasourcefactory mysql_Java基礎-DBCP連接池(BasicDataSource類)詳解

Java基礎-DBCP連接池(BasicDataSource類)詳解作者&#xff1a;尹正杰版權聲明&#xff1a;原創作品&#xff0c;謝絕轉載&#xff01;否則將追究法律責任。實際開發中“獲得連接”或“釋放資源”是非常消耗系統資源的兩個過程&#xff0c;為了解決此類性能問題&#xff0c;通常…

生物神經網絡衍生出的算法

一個生物神經網絡的基本結構&#xff1a; 生物神經網絡由大量神經元組成&#xff0c;這些神經元之間通過突觸相互連接。神經元可以接收來自其他神經元的信號&#xff0c;并根據信號的強度和類型來調整自己的輸出信號。這種神經元之間的相互連接和信號傳遞形成了生物神經網絡的基…

echart實例數據 本地加載_JVM 類加載概述

來源&#xff1a;SegmentFault 思否社區作者&#xff1a;又壞又迷人JVM簡介JVM是Java Virtual Machine(Java虛擬機)的縮寫&#xff0c;JVM是一種用于計算設備的規范&#xff0c;它是一個虛構出來的計算機&#xff0c;是通過在實際的計算機上仿真模擬各種計算機功能來實現的。Ja…

JPA / Hibernate:基于版本的樂觀并發控制

本文是Hibernate和JPA中基于版本的樂觀并發控制的簡介。 這個概念已經很老了&#xff0c;上面已經寫了很多東西&#xff0c;但是無論如何我都看到了它被重新發明&#xff0c;誤解和濫用。 我在編寫它只是為了傳播知識&#xff0c;并希望引起人們對并發控制和鎖定的興趣。 用例…

高可用集群搭建

高可用集群搭建  創建hadoop賬戶 創建hadoop賬戶&#xff08;#注意&#xff0c;接下來的操作均在hadoop賬戶下運行&#xff09; # useradd hadoop # passwd hadoopsu - hadoopmkdir soft disk1 disk2mkdir -p disk{1,2}/dfs/{dn,nn}mkdir -p disk{1,2}/nodemgr/local 將本地目…

scrt如何切換成英文版_英文版SecureCRT顯示亂碼解決

英文版SecureCRT顯示亂碼解決系統環境&#xff1a;CentOS&#xff15;.&#xff16;以前Linux都是默認安裝在英文環境下&#xff0c;用英文版的SecureCRT查看系統內容輸出的也都是英文的&#xff0c;不會出現亂碼問題。今天同事在服務器安裝時默認選擇了簡體中文&#xff0c;這…

java try catch_Java捕獲異常

大家好&#xff0c;歡迎來到樂字節小樂的Java技術分享園地在Java中&#xff0c;凡是可能拋出異常的語句&#xff0c;都可以用try ... catch捕獲。把可能發生異常的語句放在try { ... }中&#xff0c;然后使用catch捕獲對應的Exception及其子類。多catch語句可以使用多個catch語…

haproxy文件操作

import os #導入os模塊def search(): #定義查找函數 with open(haproxy.txt,r) as f: #只讀方式打開文件 value input(請輸入您…

多語言持久性:帶有MongoDB和Derby的EclipseLink

從現在開始&#xff0c;多語種持久性一直是新聞。 從2011年底開始&#xff0c;在著名的Fowler帖子的推動下&#xff0c;我看到了更多更好的主意。 最新的一個是公司內部的學生項目&#xff0c;我們在其中使用Scala作為后端數據&#xff0c;將數據持久存儲到MongoDB&#xff0c;…

web前端開發最佳實踐--(筆記之JavaScript最佳實踐)

如何避免全局變量污染&#xff1f; 避免定義全局變量或全局函數用一個變量進行封裝&#xff0c;并返回外部需要訪問的接口如何寫出高維護的js代碼 配置數據和代碼邏輯分離 如&#xff1a; 改成&#xff1a; ---用js模板mustachehandlebarsjsMVC的數據模式 model&#xff1a;數據…

yum mysql5.7位置_CentOS yum 安裝 Mysql5.7

1 Steps for a Fresh Installation of MySQL# wget https://dev.mysql.com/get/mysql57-community-release-el6-9.noarch.rpm# yum localinstall mysql57-community-release-el6-9.noarch.rpm以上步驟其實是把 MySQL Yum repository 添加到了系統的 repository list 里去了。ll…

HTML/CSS基礎知識(四)

WEB標準和W3C的理解與認識 Web標準是一系列標準的集合。 網頁主要由三部分組成&#xff1a;結構&#xff08;Structure&#xff09;、表現&#xff08;Presentation&#xff09;和行為&#xff08;Behavior&#xff09;。 對應的標準也分三方面&#xff1a;結構化標準語言主要包…

python做一個系統代碼_python初學者,用python3實現基本的學生管理系統代碼實例...

這篇文章分享了管理系統&#xff0c;python學生管理系統的使用&#xff0c;這篇文章非常詳細地介紹了通過示例代碼實現的學生管理系統&#xff0c;該系統對每個人的研究或工作都有一定的參考學習價值。 這個是用python實現的基本的增刪改查的學生管理系統吧&#xff0c;其中主要…

Python入門筆記

Python變量和數據類型 數據類型 print語句 注釋 Python的注釋以 # 開頭&#xff0c;后面的文字直到行尾都算注釋 # 這一行全部都是注釋... print hello # 這也是注釋 什么是變量 定義字符串 字符串可以用或者""括起來表示。 如果字符串本身包含怎么辦&#xff1f;比如…

1058. 選擇題(20)

原題: https://www.patest.cn/contests/pat-b-practise/1058 思路: 本題主要就是怎么讀取數據的問題, 一定要注意scanf函數匹配到 空格或者回車會結束當前變量的賦值, 并且會丟棄這個空格或回車. 關于如何判斷一項答題是否正確, 可以采用循環一個一個判斷, 也可拼成 字符串用st…