Java虛擬機內存溢出

最近在看周志明的《深入理解Java虛擬機》,雖然剛剛開始看,但是覺得還是一本不錯的書。對于和我一樣對于JVM了解不深,有志進一步了解的人算是一本不錯的書。注明:不是書托,同樣是華章出的書,質量要比《深入剖析Tomcat》高好多,起碼排版上沒有那么多嚴重的失誤,停,等哪天心情不好再噴那本書。:)(還有一本書讓我看完覺得挺不爽的,當然不排除自身問題)

剛剛看了兩章,第一章我比較關注如何自己編譯openJdk,額,現在還沒搗騰成功,完成后再分享,暫且跳過;本篇文章的主要任務是記錄書中關于產生OutOfMemoryError異常的原因。代碼以及說明基本都是出自原書,寫這篇文章意在加深印象,同時分享給那些沒有讀過這本書的人。說句自己的一次經歷,不記得是在哪家公司面試來著,面試官曾經問過我都有哪些情況會造成OutOfMemoryError異常。很遺憾,當時我不會。

設置運行時參數

說下為什么加了這樣一節,說來慚愧,第一次設置運行時參數,找不到在哪里設置,找了半天才找對位置,怕有和我一樣小白的人存在,所以就增加了這樣一個小節。(IDE工具是eclipse)

按照如下三步設置即可,呈現一場代碼的注釋中會標注每種情形需要設置的運行時參數。

step1:
step2:
step3:

可以這樣為每個含有main函數的類指定自己的運行時參數。

造成內存溢出之五大元兇

個人覺得程序員都要有”刨祖墳”的精神,文藝一點兒就是知其然,知其所以然。在日常的工作中更應該如此,不能說要實現一個功能就滿口答應,起碼要知道為什么需要這樣一個功能,解決什么問題,是否合理。如果連原因都不知道,真心不相信能把這個功能做好。也許這個也是好管理和不好管理程序員的分割線。如果說發生OutOfMemoryError跟我們無關,那我們為什么要知道發生的原因啊,美國打伊拉克我和程序員有毛關系啊。其實這個異常對大家來說應該都不陌生,之前我最愛的處理就是從新再運行一次,不行關閉eclipse,再不行重啟電腦。(殺手锏級別的解決方案).可是這樣不科學,科學的方式就要求我們知道為什么會發生這個異常,換句話說是發生這個異常的場景,然后通過打印出的異常信息快速定位發生內存溢出的區域,然后進行權衡,調整運行時參數來解決。

Java堆溢出

Java堆用于存儲對象實例,知道這一點就很容易呈現堆溢出,不斷的創建對象,并且保持有指向其的引用,防止為gc。

代碼如下:

  import java.util.ArrayList;
import java.util.List;
/**
   * VM Args:-Xms20M -Xmx20M -XX:+HeapDumpOnOutOfMemoryError
   *
   */
public class HeapOOM {
static class OOMObject{
}
public static void main(String[] args) {
List<OOMObject> list = new ArrayList<OOMObject>();
while(true){
list.add(new OOMObject());
}
}
}

通過設置-Xms20M -Xmx20M都為20M意在防止堆大小自動擴展,更好的展現溢出。 執行結果如下:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

是不是很明顯啊,顯示堆空間發生OutOfMemoryError。

書中告訴我們發生了OutOfMemoryError后,通常是通過內存影像分析工具對dump出來的堆轉儲快照進行分析(這就是運行時參數中配置-XX:+HeapDumpOnOutOfMemoryError的原因),重點是確定是由內存泄露(Memory Leak)還是有內存溢出(Memory Overflow)引起的OutOfMemoryError。如果是內存泄露則找到泄露點,修正;如果確實是合理的存在,那么就增加堆空間。(內存分析這里我也木有做過,工具也木有使用過,在后續章節會有介紹,用熟了后再來一篇)

虛擬機棧和本地方法棧溢出

由于在HotSpot虛擬機中并不區分虛擬機棧和本地方法區棧,因此對于HotSpot來說,-Xoss(設置本地方法棧大小)參數是無效的,棧容量由-Xss參數設定。關于虛擬機棧和本地方法區棧,在Java虛擬機規范中描述了兩種異常:

  • 如果線程請求的棧深度大于虛擬機所允許的最大深度,將拋出StackOverflowError異常
  • 如果虛擬機在擴展棧時無法申請到足夠的內存空間,則拋出OutOfMemoryError異常

    書中談到單線程的場景下只能浮現StackOverflowError,那我們就先來看看單線程場景下到底會是什么樣子。

    /**
     * 
     * VM Args:-Xss128k
     */
    public class JavaVMStackSOF {
    private int stackLength = 1;
    private void stackLeak() {
    stackLength++;
    stackLeak();
    }
    public static void main(String[] args) throws Throwable {
    JavaVMStackSOF oom = new JavaVMStackSOF();
    try {
    oom.stackLeak();
    } catch (Throwable e) {
    System.out.println("stack length:" + oom.stackLength);
    throw e;
    }
    }
    }
    

    通過-Xss128k設置虛擬機棧大小為128k,執行結果如下:

    執行結果顯示,確實是發生了StackOverflowError異常。

    通過不斷創建線程耗盡內存也可以呈現出OutOfMemoryError異常,但是在Windows平臺下模擬會使系統死機,我這里就不多說了。感興趣的可以自己去嘗試。

    運行時常量池溢出

    向運行時常量池中添加內容最簡單的方式就是使用String.intern()方法。由于常量池分配在方法區內,可以通過-XX:PermSize和-XX:MaxPermSize限制方法區的大小,從而間接限制其中常量池的容量。

    代碼如下:

      import java.util.ArrayList;
    import java.util.List;
    /**
       * VM Args:-XX:PermSize=10M -XX:MaxPermSize=10M
       * 
       */
    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());
    }
    }
    }
    

    這里有個小小的插曲,之前有聽說在jdk7中將永久區(方法區和常量池)給干掉了,沒有驗證過。永久區可以說是在堆之上的一個邏輯分區。如果jdk7中去掉了,那么這個示例應該會拋出堆空間的內存溢出,而非運行時常量池的內存溢出。所以在執行程序的時候分別用了jdk6和jdk7兩個版本。多說一句,如果jdk7去掉了方法區,那么-XX:PermSize=10M -XX:MaxPermSize=10M就不起作用了,所以在jdk7環境下運行時,堆大小為jvm默認的大小,要執行一會兒(半小時左右:( ))才能拋出異常。沒關系,再配置下運行時參數即可,注意要配置成不可擴展。以圖為據:

  • jdk6環境下拋出運行時常量池內存溢出
    Exception in thread "main" java.lang.OutOfMemoryError: PermGen space

    顯而易見PermGen space,永久區。不解釋。

  • jdk7環境下,運行時參數為:-XX:PermSize=10M -XX:MaxPermSize=10M
    Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

    運行了好久好久,最終拋出堆內存溢出。Java heap space已經足夠說明問題了。

  • jdk7環境下,運行時參數為:-verbose:gc -Xms20M -Xmx20M -XX:+HeapDumpOnOutOfMemoryError
    Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

    同樣也是堆內存溢出,不過速度就快了好多好多,因為堆大小被設置為不可擴展。

    方法區溢出

    方法區用于存放Class的相關信息,如類名、訪問修飾符、常量池、字段描述、方法描述等。測試這個區域只要在運行時產生大量的類填滿方法區,知道溢出。書中借助CGlib直接操作字節碼運行時,生成了大量的動態類。

    當前主流的Spring和Hibernate對類進行增強時,都會使用到CGLib這類字節碼技術,增強的類越多,就需要越大的方法區來保證動態生成的Class可以加載到內存。

    測試代碼如下:

      import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    /**
       * VM Args:-XX:PermSize=10M -XX:MaxPermSize=10M
       *
       */
    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 object, Method method,
    Object[] args, MethodProxy proxy) throws Throwable{
    return proxy.invokeSuper(object, args);
    }
    });
    enhancer.create();
    }
    }
    static class OOMObject {
    }
    }
    

    工程中要引入cglib-2.2.2.jar和asm-all-3.3.jar。

    方法區的內存溢出問題同樣存在jdk6和jdk7版本之間的區別,同運行時常量池內存溢出。

    方法區溢出也是一種常見的內存溢出異常,一個類如果要被垃圾收集器回收掉,判定條件是非常苛刻的。在經常動態生成大量Class的應用中,需要特別注意類的回收狀況。這類場景除了上面提到的程序使用了CGLib字節碼增強外,常見的還有:大量JSP或動態生成JSP文件的應用、基于OSGi的應用等。

    本機直接內存溢出

    DirectMemory容量可以通過-XX:MaxDirectMemorySize指定。

    示例代碼如下:

      import java.lang.reflect.Field;
    import sun.misc.Unsafe;
    /**
       * VM Args:-Xmx20M -XX:MaxDirectMemorySize=10M
       *
       */
    public class DirectMemoryOOM {
    private static final int _1MB = 1024 * 1024;
    /**
         * @param args
         * @throws IllegalAccessException
         * @throws IllegalArgumentException
         */
    public static void main(String[] args) throws IllegalArgumentException,
    IllegalAccessException {
    // TODO Auto-generated method stub
    Field unsafeField = Unsafe.class.getDeclaredFields()[0];
    unsafeField.setAccessible(true);
    Unsafe unsafe = (Unsafe) unsafeField.get(null);
    while(true){
    unsafe.allocateMemory(_1MB);
    }
    }
    }
    

    運行結果如下圖:

    拋出內存溢出異常。不解釋。

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

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

相關文章

spring boot構建

1.新建Maven工程 1.File-->new-->project-->maven project 2.webapp 3.工程名稱 k3 2.Maven 三個常用命令 選 項目右擊- >run-> Maven clean&#xff0c;一般新工程&#xff0c;新導入工程用這個命令清理clean Mvaen install&#xff0c; Maven test&#xff0c…

用戶輸入漢字時計算機首先將,用戶輸入漢字時,計算機首先將漢字的輸入碼轉換為__________。...

用戶的蓄的形能器常見式有。輸入時計算機首先輸入包括藥物具有基的酚羥。漢字換物包腺皮括質激腎上素藥。對既荷又有線有相間負負荷時&#xff0c;將漢倍作為等選取相負效三相負荷乘荷最大&#xff0c;將漢相負荷換荷應先將線間負算為&#xff0c;效三相負荷時在計算等&#xf…

從最終用戶角度來看外部結構_從不同角度來看您最喜歡的游戲

從最終用戶角度來看外部結構The complete python code and Exploratory Data Analysis Notebook are available at my github profile;完整的python代碼和Exploratory Data Analysis Notebook可在我的github個人資料中找到 &#xff1b; Pokmon is a Japanese media franchise,…

apache+tomcat配置

無意間看到tomcat 6集群的內容&#xff0c;就嘗試配置了一下&#xff0c;還是遇到很多問題&#xff0c;特此記錄。apache服務器和tomcat的連接方法其實有三種:JK、http_proxy和ajp_proxy。本文主要介紹最為常見的JK。 環境&#xff1a;PC2臺&#xff1a;pc1(IP 192.168.88.118…

記自己在spring中使用redis遇到的兩個坑

本人在spring中使用redis作為緩存時&#xff0c;遇到兩個坑&#xff0c;現在記錄如下&#xff0c;算是作為自己的備忘吧&#xff0c;文筆不好&#xff0c;望大家見諒&#xff1b; 一、配置文件 1 <!-- 加載Properties文件 -->2 <bean id"configurer" cl…

Azure實踐之如何批量為資源組虛擬機創建alert

通過上一篇的簡介&#xff0c;相信各位對于簡單的創建alert&#xff0c;以及Azure monitor使用以及大概有個印象了。基礎的使用總是非常簡單的&#xff0c;這里再分享一個常用的alert使用方法實際工作中&#xff0c;不管是日常運維還是做項目&#xff0c;我們都需要知道VM的實際…

南信大濱江學院計算機基礎,南京信息工程大學濱江學院計算機基礎期末復習知識點...

《計算機基礎》期末考試復習知識點第一章計算機基礎知識1.第一臺電子計算機的名稱、誕生時間及運算性能&#xff1b;名稱&#xff1a;電子數字積分計算機ENIAC(埃尼阿克)。誕生時間&#xff1a;1946年2月14日。運算性能&#xff1a;運算速度為每秒5000次加法。2.計算機發展四個…

nginx集群

今天看到"基于apache的tomcat負載均衡和集群配置 "這篇文章成為javaEye熱點。 略看了一下&#xff0c;感覺太復雜&#xff0c;要配置的東西太多&#xff0c;因此在這里寫出一種更簡潔的方法。 要集群tomcat主要是解決SESSION共享的問題&#xff0c;因此我利用memc…

管道過濾模式 大數據_大數據管道配方

管道過濾模式 大數據介紹 (Introduction) If you are starting with Big Data it is common to feel overwhelmed by the large number of tools, frameworks and options to choose from. In this article, I will try to summarize the ingredients and the basic recipe to …

DevOps時代,企業數字化轉型需要強大的工具鏈

伴隨時代的飛速進步&#xff0c;中國的人口紅利帶來了互聯網業務的快速發展&#xff0c;巨大的流量也帶動了技術的不斷革新&#xff0c;研發的模式也在不斷變化。傳統企業紛紛效仿互聯網的做法&#xff0c;結合DevOps進行數字化的轉型。通常提到DevOps&#xff0c;大家浮現在腦…

2018.09.21 atcoder An Invisible Hand(貪心)

傳送門 簡單貪心啊。 這題顯然跟t并沒有關系&#xff0c;取差量最大的幾組買入賣出就行了。 于是我們統計一下有幾組差量是最大的就行了。 代碼&#xff1a; #include<bits/stdc.h> #define N 100005 using namespace std; inline int read(){int ans0;char chgetchar();…

嘉應學院專插本計算機專業考綱,2015年嘉應學院漢語言文學專插本寫作大綱.pdf...

.2015 專插本基礎寫作輔導部分分為五個部分&#xff0c;共 42 道題目。 50 &#xfe6a;-60 &#xfe6a;﹙填空&#xff0c;選擇&#xff0c;判斷&#xff0c;名詞解釋&#xff0c;簡答&#xff0c;鑒賞﹚&#xff0c; 40 &#xfe6a;﹙作文﹚。1、什么是文章寫作。文章寫作是…

綠色版本Tomcat

解壓版Tomcat配置(本例Tomcat6)&#xff1a;一 配置Tomcat1 下載Tomcat Zip壓縮包&#xff0c;解壓。如果增加tomcat的用戶名和密碼&#xff0c;則修改/conf/tomcat-user.xml<?xml version1.0 encodingutf-8?><tomcat-users><role rolename"manager"…

[ BZOJ 2160 ] 拉拉隊排練

\(\\\) \(Description\) 一個由小寫字母構成的長為\(N\)的字符串&#xff0c;求前\(K\)長的奇數長度回文子串長度之積&#xff0c;對\(19930726\)取模后的答案。 \(N\in [1,10^6]\)&#xff0c;\(K\in [1,10^{12}]\)\(\\\) \(Solution\) \(Manacher\)處理出所有位置的回文半徑&…

用戶體驗可視化指南pdf_R中增強可視化的初學者指南

用戶體驗可視化指南pdfLearning to build complete visualizations in R is like any other data science skill, it’s a journey. RStudio’s ggplot2 is a useful package for telling data’s story, so if you are newer to ggplot2 and would love to develop your visua…

nodeJS 開發微信公眾號

準備測試公眾號 mp.weixin.qq.com/debug/cgi-b… 關注&#xff0c;獲取測試公眾號 內網滲透工具 natapp.cn/login 按照教程下載客戶端進行配置 后臺服務接入公眾號 有netapp 生成的映射外網IP > URL 搭建express開發環境 這個網上有教程&#xff0c;自行百度 接口配置和簽名…

單招計算機應用基礎知識考試,四川郵電職業技術學院單招計算機應用基礎考試大綱...

2021年高職單招升學一對一咨詢小藝老師:18290437291(微信)四川郵電職業技術學院單招計算機應用基礎考試大綱一、考試性質本技能考試是中等職業學校(含普通中專、職業高中、技工學校和成人中專)信息技術類專業畢業生參加四川郵電職業技術學院2016年單獨招生考試。二、考試依據1.…

linux掛載磁盤陣列

linux掛載磁盤陣列 在許多項目中&#xff0c;都會把數據存放于磁盤陣列&#xff0c;以確保數據安全或者實現負載均衡。在初始安裝數據庫系統和數據恢復時&#xff0c;都需要先掛載磁盤陣列到系統中。本文記錄一次在linux系統中掛載磁盤的操作步驟&#xff0c;以及注意事項。 此…

dedecms ---m站功能基礎詳解

織夢2015年6月8日更新后&#xff0c;就添加了很多針對手機移動端的設計&#xff0c;最大的設計就是添加了生成二維碼的織夢標簽和織夢手機模板功能&#xff0c;織夢更新后&#xff0c;默認的 default模板中就包含手機模板&#xff0c;所以我們可以給織夢網站設計雙模板&#xf…

一個小菜鳥給未來的菜鳥們的一丟丟建議

寫這篇文章的主要原因是有個建筑行業的朋友覺得搞建筑身累心累&#xff0c;想轉到我們這個it行業來加入我們的編程大軍中&#xff0c;找我咨詢了一哈。在我了解了他的邏輯和理科這方面只是一般般的基礎上&#xff0c;我給他的建議是&#xff1a;學習前端&#xff0c;而不是后端…