欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java內(nèi)存溢出案例模擬和原理分析過(guò)程

 更新時(shí)間:2020年04月07日 08:48:44   作者:Chsoul''S Blog  
這篇文章主要介紹了Java內(nèi)存溢出案例模擬和原理分析過(guò)程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下

在JVM虛擬機(jī)規(guī)范中,Java虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū)域除了程序計(jì)數(shù)器(Program Counter Register)外都有可能出現(xiàn)OutOfMemoryError的情況,使用Hotspot虛擬機(jī)簡(jiǎn)單的模擬堆棧內(nèi)存溢出的場(chǎng)景,方便快速定位是什么區(qū)域的內(nèi)存溢出。

通過(guò)VM參數(shù)設(shè)置Java堆的大小,避免堆可擴(kuò)展內(nèi)存(設(shè)定-Xms和Xmx一樣可避免堆自動(dòng)擴(kuò)展);

通過(guò)設(shè)定-XX:+HeapDumpOnOutOf-MemoryError可以讓虛擬機(jī)在出現(xiàn)內(nèi)存溢出異常的時(shí)候Dump出當(dāng)前的內(nèi)存堆轉(zhuǎn)儲(chǔ)快照。

/**
 * VM Args:-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
 * @author Vicente
 * @version 1.0
 * @date 2020/4/5 10:28
 */
public class TestHeapOOM {
 public static void main(String[] args) {

  List<TestHeapOOM> list = new ArrayList<TestHeapOOM>();
  while (true) {
   list.add(new TestHeapOOM());
  }
 }
}

設(shè)置啟動(dòng)參數(shù):-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError

運(yùn)行結(jié)果:

java.lang.OutOfMemoryError: Java heap space
 Dumping heap to java_pid3676.hprof ...
 Heap dump file created [28279988 bytes in 0.099 secs]
 Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
 at java.util.Arrays.copyOf(Arrays.java:3210)
 at java.util.Arrays.copyOf(Arrays.java:3181)
 at java.util.ArrayList.grow(ArrayList.java:265)
 at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:239)
 at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:231)
 at java.util.ArrayList.add(ArrayList.java:462)
 at com.oom.TestHeapOOM.main(TestHeapOOM.java:19)

使用IDEA和Eclipse都可以設(shè)置啟動(dòng)時(shí)的參數(shù)。

堆轉(zhuǎn)儲(chǔ)快照文件一般生成后位于你的work space,拿到文件后要對(duì)快照文件進(jìn)行分析,可以采用不同的工具來(lái)幫助我們分析,這里推薦兩種:

jhat

在IDEA或者Eclispe的終端控制臺(tái)直接輸入命令

jhat java_pid13232.hprof

當(dāng)dump的文件過(guò)大時(shí)需要設(shè)置jhat參數(shù):jhat -J-Xmx2048m java_pid13232.hprof,默認(rèn)-Xmx為1024

對(duì)堆快照進(jìn)行分析

Reading from java_pid13232.hprof...
Dump file created Sun Apr 05 10:54:06 CST 2020
Snapshot read, resolving...
Resolving 818818 objects...
Chasing references, expect 163
dots................................................................................................................
Eliminating duplicate
references..........................................................................................................
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.

通過(guò)訪問(wèn)http://localhost:7000即可查看分析結(jié)果,對(duì)象內(nèi)存分配的大小等信息。

mat

工具下載地址:https://eclipse.org/mat/downloads.php,選擇需要下載的版本,windows版本下載后是一個(gè)壓縮包,直接解壓運(yùn)行即可。

打開(kāi)需要分析的堆轉(zhuǎn)儲(chǔ)文件,分析后會(huì)展示一個(gè)概要預(yù)覽

Leak Suspects » Leaks » Problem Suspect 在這里面可以看到對(duì)象的個(gè)數(shù),對(duì)象占用大小等信息,這里包含兩個(gè)重要信息

Generally speaking, shallow heap of an object is its size in the heap and retained size of the same object is the amount of heap memory that will be freed when the object is garbage collected.

具體解釋可以參考:https://help.eclipse.org/2020-03/index.jsp

復(fù)制代碼 代碼如下:
- Shallow Heap:某個(gè)對(duì)象自身大小,不包含其引用對(duì)象的大??;- Retained Heap:某個(gè)對(duì)象在發(fā)生GC回收時(shí),如果被釋放,其釋放內(nèi)存的大小,這就要包含其引用的對(duì)象占用堆內(nèi)存的大小。

這里具體使用就不再描述,可以參考官方文檔。

Java運(yùn)行時(shí)數(shù)據(jù)區(qū)包含虛擬機(jī)棧和本地方法棧,在Hotspot虛擬機(jī)實(shí)現(xiàn)中對(duì)于本地方法棧的參數(shù)(-Xoss)設(shè)定并無(wú)實(shí)際效果,只通過(guò)-Xss參數(shù)來(lái)模擬棧的內(nèi)存溢出。《Java虛擬機(jī)規(guī)范》中指出:

如果線程請(qǐng)求的棧深度大于虛擬機(jī)所允許的最大深度,拋出StackOverflowError異常如果虛擬機(jī)的棧內(nèi)存允許動(dòng)態(tài)擴(kuò)展,當(dāng)擴(kuò)展棧容量無(wú)法申請(qǐng)到足夠的內(nèi)存時(shí),拋出OutOfMemoryError異常

設(shè)置運(yùn)行參數(shù)VM Args:-Xss128k

/**
 * VM Args:-Xss128k
 * @author Vicente
 * @version 1.0
 * @date 2020/4/5 12:39
 */
public class TestStackOverflow {

 private int stackLength = 1;
 
 public void stackLeak() {
  stackLength++;
  stackLeak();
 }

 public static void main(String[] args) throws Throwable {
  TestStackOverflow overflow = new TestStackOverflow();
  try {
   overflow.stackLeak();
  } catch (Throwable e) {
   System.out.println("stack length:" + overflow.stackLength);
   throw e;
  }
 }
}

運(yùn)行結(jié)果:

Exception in thread "main" java.lang.StackOverflowError
at com.oom.TestStackOverflow.stackLeak(TestStackOverflow.java:17)
at com.oom.TestStackOverflow.stackLeak(TestStackOverflow.java:17)
//省略...
stack length:36984
//省略...

根據(jù)操作系統(tǒng)的不同和Java虛擬機(jī)版本的不同,棧容量的最小值也會(huì)有所不同,改變棧容量的大小或者棧幀過(guò)大時(shí)都會(huì)導(dǎo)致StackOverflowError異常。

Hotspot虛擬機(jī)不支持?jǐn)U展棧內(nèi)存,除非在創(chuàng)建線程申請(qǐng)內(nèi)存就不足會(huì)導(dǎo)致OutOfMemoryError異常,其他情況都是在運(yùn)行時(shí)因?yàn)闂H萘繜o(wú)法容納新的棧幀而導(dǎo)致StackOverflowError異常。

不同的虛擬機(jī)實(shí)現(xiàn)有著不同的細(xì)節(jié)處理,其他虛擬機(jī)實(shí)現(xiàn)如果是可擴(kuò)容??臻g,棧容量不足時(shí)會(huì)拋出OutOfMemoryError異常,當(dāng)遇到OutOfMemoryError時(shí)要先判斷是??臻g還是堆內(nèi)存的異常。

方法區(qū)

在JDK6之前的Hotspot虛擬機(jī)中方法區(qū)被設(shè)置在永久代中,運(yùn)行時(shí)常量池也屬于方法區(qū)的一部分,可以通過(guò)-XX:PermSize和-XX:MaxPermSize限制永久代的大小,在JDK7開(kāi)始逐步的去永久代,到了JDK8就開(kāi)始使用元空間(meta-space)來(lái)實(shí)現(xiàn)方法區(qū),保存程序運(yùn)行時(shí)的數(shù)據(jù)。

使用JDK6,設(shè)定永久代參數(shù)-XX:PermSize=2M -XX:MaxPermSize=2M

public class TestConstantPoolOOM {
 public static void main(String[] args) throws Throwable {
  //使用Set保持著常量池引用,避免Full GC回收常量池行為
  Set<String> set = new HashSet<String>();
  // 在short范圍內(nèi)足以讓6MB的PermSize產(chǎn)生OOM了
  short i = 0;
  while (true) {
   set.add(String.valueOf(i++).intern());
   //String.valueOf(i++).intern();
  }
 }
}

運(yùn)行結(jié)果:

Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
at java.lang.String.intern(Native Method)
at com.oom.TestConstantPoolOOM.main(TestConstantPoolOOM.java from InputFileObject:21)

可以看到OutOfMemoryError后面指明了內(nèi)存溢出的位置PermGen space;在JDK8中使用-XX:MaxMeta-spaceSize參數(shù)把方法區(qū)容量同樣限制,也不會(huì)出現(xiàn)異常,因?yàn)閺腏DK7開(kāi)始常量池已經(jīng)從永久代移到了Java堆的位置,此時(shí)限制Java堆的大小便會(huì)拋出異常,定位異常的位置。

設(shè)置上面代碼的運(yùn)行參數(shù):-Xms6m -Xmx6m

運(yùn)行結(jié)果:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.HashMap.resize(HashMap.java:704)
at java.util.HashMap.putVal(HashMap.java:663)
at java.util.HashMap.put(HashMap.java:612)
at java.util.HashSet.add(HashSet.java:220)
at com.oom.TestConstantPoolOOM.main(TestConstantPoolOOM.java:20)

可以看到,程序運(yùn)行拋出java.lang.OutOfMemoryError異常。

方法區(qū)的異常也是一種常見(jiàn)異常,一個(gè)類被垃圾回收期回收的條件是比較苛刻的,在經(jīng)常運(yùn)行時(shí)生成大量動(dòng)態(tài)類的應(yīng)用場(chǎng)景里,就應(yīng)該特別關(guān)注這些類的回收狀況,比如傳統(tǒng)項(xiàng)目中大量的jsp文件,jsp會(huì)被編譯成Java類,容易拋出方法區(qū)異常,在JDK8以后永久代不再存在,元空間的出現(xiàn)使得,正常創(chuàng)建對(duì)象的過(guò)程很難出現(xiàn)方法區(qū)的內(nèi)存溢出,不過(guò)Hotspot也提供了一些參數(shù)設(shè)置保護(hù)元空間。

- XX:MaxMetaspaceSize:設(shè)置元空間最大值,默認(rèn)是-1,即不限制,或者說(shuō)只受限于本地內(nèi)存大小。
- XX:MetaspaceSize:指定元空間的初始空間大小,以字節(jié)為單位,達(dá)到該值就會(huì)觸發(fā)垃圾收集,收集器會(huì)對(duì)該值進(jìn)行調(diào)整:如果釋放大量的空間,適當(dāng)降低該值;如果釋放了很少的空間,在不超過(guò)-XX:MaxMetaspaceSize(如果設(shè)置了的話)的情況下,適當(dāng)提高該值。
- XX:MinMetaspaceFreeRatio:作用是在垃圾收集之后控制最小的元空間剩余容量的百分比,可減少因?yàn)樵臻g不足導(dǎo)致的垃圾收集的頻率。
- XX:Max-MetaspaceFreeRatio,用于控制最大的元空間剩余容量的百分比。

直接內(nèi)存

直接內(nèi)存可以理解為堆外內(nèi)存,通過(guò)參數(shù)-XX:MaxDirectMemorySize來(lái)設(shè)定,如果不設(shè)置默認(rèn)與Java堆內(nèi)存的最大值相同。NIO會(huì)使用直接內(nèi)存,使用Unsafe類來(lái)模擬直接內(nèi)存溢出的情況。

public class TestDirectMemoryOOM {
 private static final int _1MB = 1024 * 1024;
 public 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.allocateMemory(_1MB);
  }
 }
}

運(yùn)行結(jié)果:

Exception in thread "main" java.lang.OutOfMemoryError
at sun.misc.Unsafe.allocateMemory(Native Method)
at com.oom.TestDirectMemoryOOM.main(TestDirectMemoryOOM.java:24)

當(dāng)直接內(nèi)存溢出時(shí),Dump文件并沒(méi)有太多錯(cuò)誤信息,要考慮是否間接使用NIO了。

總結(jié)當(dāng)Java虛擬機(jī)拋出OutOfMemoryError錯(cuò)誤時(shí),判斷是Java內(nèi)存哪一塊區(qū)域拋出的錯(cuò)誤,定位堆,棧使用工具分析堆轉(zhuǎn)儲(chǔ)快照,判斷是內(nèi)存泄漏(Memory Leak)還是內(nèi)存溢出(Memory Overflow)當(dāng)發(fā)生內(nèi)存泄漏可以通過(guò)工具查看GC Roots引用鏈,分析為什么垃圾回收器無(wú)法回收,判定對(duì)象創(chuàng)建的位置,是否有可回收對(duì)象如果是內(nèi)存溢出,根據(jù)硬件性能是否可以(使用-Xms和-Xmx)擴(kuò)展堆內(nèi)存大小,或者從代碼角度去優(yōu)化

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • javaweb實(shí)現(xiàn)文件上傳功能

    javaweb實(shí)現(xiàn)文件上傳功能

    這篇文章主要為大家詳細(xì)介紹了javaweb實(shí)現(xiàn)文件上傳功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • 在Spring-Boot中如何使用@Value注解注入集合類

    在Spring-Boot中如何使用@Value注解注入集合類

    這篇文章主要介紹了在Spring-Boot中如何使用@Value注解注入集合類的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • Java實(shí)現(xiàn)常用加密算法SM3的方式及測(cè)試代碼

    Java實(shí)現(xiàn)常用加密算法SM3的方式及測(cè)試代碼

    這篇文章介紹了SM3算法在Java中的實(shí)現(xiàn)方式,SM3算法是一種密碼散列函數(shù)標(biāo)準(zhǔn),主要用于商用密碼應(yīng)用中的數(shù)字簽名和驗(yàn)證、消息認(rèn)證碼生成和驗(yàn)證、隨機(jī)數(shù)生成等,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-10-10
  • Spring AOP的使用詳解

    Spring AOP的使用詳解

    這篇文章主要介紹了Spring AOP的使用詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • SpringBoot打成jar包瘦身方法總結(jié)

    SpringBoot打成jar包瘦身方法總結(jié)

    springBoot打包的時(shí)候代碼和jar包打包在同一個(gè)jar包里面,會(huì)導(dǎo)致jar包非常龐大,下面這篇文章主要給大家介紹了關(guān)于SpringBoot打的jar包瘦身方法的相關(guān)資料,需要的朋友可以參考下
    2022-12-12
  • 最新版Spring Security中的路徑匹配方案

    最新版Spring Security中的路徑匹配方案

    在 Spring Security 中,路徑匹配是權(quán)限控制的核心部分,它決定了哪些請(qǐng)求可以訪問(wèn)特定的資源,本文將詳細(xì)介紹 Spring Security 中的路徑匹配策略,并提供相應(yīng)的代碼示例,需要的朋友可以參考下
    2024-04-04
  • Java流程控制之循環(huán)結(jié)構(gòu)while、do...while

    Java流程控制之循環(huán)結(jié)構(gòu)while、do...while

    這篇文章主要介紹了Java流程控制之循環(huán)結(jié)構(gòu)while及do...while,文章除了講解循環(huán)結(jié)構(gòu)while和do...while之外,還講解了他們之間的區(qū)別,下面我們就一起進(jìn)入文章講解更多詳細(xì)內(nèi)容吧
    2021-12-12
  • springboot-controller的使用詳解

    springboot-controller的使用詳解

    本篇文章主要介紹了springboot-controller的使用詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-08-08
  • mybatis中的if-else及if嵌套使用方式

    mybatis中的if-else及if嵌套使用方式

    這篇文章主要介紹了mybatis中的if-else及if嵌套使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Java匿名類和匿名函數(shù)的概念和寫(xiě)法

    Java匿名類和匿名函數(shù)的概念和寫(xiě)法

    匿名函數(shù)寫(xiě)法和匿名類寫(xiě)法的前提必須基于函數(shù)式接口匿名函數(shù)寫(xiě)法和匿名類寫(xiě)法其本質(zhì)是同一個(gè)東西,只是簡(jiǎn)化寫(xiě)法不同使用Lambda表達(dá)式簡(jiǎn)寫(xiě)匿名函數(shù)時(shí),可以同時(shí)省略實(shí)現(xiàn)類名、函數(shù)名,這篇文章主要介紹了Java匿名類和匿名函數(shù)的概念和寫(xiě)法,需要的朋友可以參考下
    2023-06-06

最新評(píng)論