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

Java內(nèi)存溢出實(shí)現(xiàn)原因及解決方案

 更新時(shí)間:2020年03月24日 09:58:35   作者:天際星痕  
這篇文章主要介紹了Java內(nèi)存溢出實(shí)現(xiàn)原因及解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下

1.JVM Heap(堆)溢出:java.lang.OutOfMemoryError: Java heap space

JVM在啟動(dòng)的時(shí)候會(huì)自動(dòng)設(shè)置JVM Heap的值, 可以利用JVM提供的-Xmn -Xms -Xmx等選項(xiàng)可進(jìn)行設(shè)置。Heap的大小是Young Generation 和Tenured Generaion 之和。在JVM中如果98%的時(shí)間是用于GC,且可用的Heap size 不足2%的時(shí)候?qū)伋龃水惓P畔ⅰ?br /> 解決方法:手動(dòng)設(shè)置JVM Heap(堆)的大小。

Java堆用于儲(chǔ)存對(duì)象實(shí)例。當(dāng)需要為對(duì)象實(shí)例分配內(nèi)存,而堆的內(nèi)存占用又已經(jīng)達(dá)到-Xmx設(shè)置的最大值。將會(huì)拋出OutOfMemoryError異常。例子如下:

package com.demo.test;

import java.util.ArrayList;
import java.util.List;

/**
 * VM Args: -Xms5m -Xmx5m
 */
public class HeapOOM {
  
  public static void main(String[] args) {
    int count = 0;
    List<Object> list = new ArrayList<Object>();
    while(true){
      list.add(new Object());
      System.out.println(++count);
    }
  }

}

然后在運(yùn)行時(shí)設(shè)置jvm參數(shù),如下:

-Xmx為5m。其中的一次測(cè)試結(jié)果為,當(dāng)count的值累加到360145時(shí),發(fā)生如下異常:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:2245)
at java.util.Arrays.copyOf(Arrays.java:2219)
at java.util.ArrayList.grow(ArrayList.java:213)
at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:187)
at java.util.ArrayList.add(ArrayList.java:411)
at com.demo.test.HeapOOM.main(HeapOOM.java:12)

修改-Xmx為10m。其中的一次測(cè)試結(jié)果為,當(dāng)count的值累加到540217時(shí),發(fā)生OutOfMemoryError異常。隨著-Xmx參數(shù)值的增大,java堆中可以存儲(chǔ)的對(duì)象也越多。

2.PermGen space溢出: java.lang.OutOfMemoryError: PermGen space

PermGen space的全稱是Permanent Generation space,是指內(nèi)存的永久保存區(qū)域。為什么會(huì)內(nèi)存溢出,這是由于這塊內(nèi)存主要是被JVM存放Class和Meta信息的,Class在被Load的時(shí)候被放入PermGen space區(qū)域,它和存放Instance的Heap區(qū)域不同,sun的 GC不會(huì)在主程序運(yùn)行期對(duì)PermGen space進(jìn)行清理,所以如果你的APP會(huì)載入很多CLASS的話,就很可能出現(xiàn)PermGen space溢出。一般發(fā)生在程序的啟動(dòng)階段。
解決方法: 通過(guò)-XX:PermSize和-XX:MaxPermSize設(shè)置永久代大小即可。

方法區(qū)用于存放java類型的相關(guān)信息,如類名、訪問(wèn)修飾符、常量池、字段描述、方法描述等。在類裝載器加載class文件到內(nèi)存的過(guò)程中,虛擬機(jī)會(huì)提取其中的類型信息,并將這些信息存儲(chǔ)到方法區(qū)。當(dāng)需要存儲(chǔ)類信息而方法區(qū)的內(nèi)存占用又已經(jīng)達(dá)到-XX:MaxPermSize設(shè)置的最大值,將會(huì)拋出OutOfMemoryError異常。對(duì)于這種情況的測(cè)試,基本的思路是運(yùn)行時(shí)產(chǎn)生大量的類去填滿方法區(qū),直到溢出。這里需要借助CGLib直接操作字節(jié)碼運(yùn)行時(shí),生成了大量的動(dòng)態(tài)類。例子如下:

package com.demo.test;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodProxy;
import net.sf.cglib.proxy.MethodInterceptor;

/**
 * VM Args: -XX:PermSize=10M -XX:MaxPermSize=10M
 */
public class MethodAreaOOM {

  public static void main(String[] args) {
    int count = 0;
    while (true) {
      Enhancer enhancer = new Enhancer();
      enhancer.setSuperclass(MethodAreaOOM.class);
      enhancer.setUseCache(false);
      enhancer.setCallback(new MethodInterceptor() {
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
          return proxy.invoke(obj, args);
        }
      });
      enhancer.create();
      System.out.println(++count);
    }
  }

}

-XX:MaxPermSize為10m。其中的一次測(cè)試結(jié)果為,當(dāng)count的值累加到800時(shí),發(fā)生如下異常:

復(fù)制代碼 代碼如下:
Caused by: java.lang.OutOfMemoryError: PermGen space at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:792) ... 8 more

隨著-XX:MaxPermSize參數(shù)值的增大,java方法區(qū)中可以存儲(chǔ)的類型數(shù)據(jù)也越多。

3.棧溢出: java.lang.StackOverflowError : Thread Stack space

棧溢出了,JVM依然是采用棧式的虛擬機(jī),這個(gè)和C和Pascal都是一樣的。函數(shù)的調(diào)用過(guò)程都體現(xiàn)在堆棧和退棧上了。調(diào)用構(gòu)造函數(shù)的 “層”太多了,以致于把棧區(qū)溢出了。 通常來(lái)講,一般棧區(qū)遠(yuǎn)遠(yuǎn)小于堆區(qū)的,因?yàn)楹瘮?shù)調(diào)用過(guò)程往往不會(huì)多于上千層,而即便每個(gè)函數(shù)調(diào)用需要 1K的空間(這個(gè)大約相當(dāng)于在一個(gè)C函數(shù)內(nèi)聲明了256個(gè)int類型的變量),那么棧區(qū)也不過(guò)是需要1MB的空間。通常棧的大小是1-2MB的。通俗一點(diǎn)講就是單線程的程序需要的內(nèi)存太大了。 通常遞歸也不要遞歸的層次過(guò)多,很容易溢出。

解決方法:1:修改程序。2:通過(guò) -Xss: 來(lái)設(shè)置每個(gè)線程的Stack大小即可。

在Java虛擬機(jī)規(guī)范中,對(duì)這個(gè)區(qū)域規(guī)定了兩種異常狀況:StackOverflowError和OutOfMemoryError異常。

(1)StackOverflowError異常

每當(dāng)java程序代碼啟動(dòng)一個(gè)新線程時(shí),Java虛擬機(jī)都會(huì)為它分配一個(gè)Java棧。Java棧以幀為單位保存線程的運(yùn)行狀態(tài)。當(dāng)線程調(diào)用java方法時(shí),虛擬機(jī)壓入一個(gè)新的棧幀到該線程的java棧中。只要這個(gè)方法還沒(méi)有返回,它就一直存在。

如果線程的方法嵌套調(diào)用層次太多(如遞歸調(diào)用),隨著java棧中幀的逐漸增多,最終會(huì)由于該線程java棧中所有棧幀大小總和大于-Xss設(shè)置的值,而產(chǎn)生StackOverflowError內(nèi)存溢出異常。例子如下:

package com.demo.test;
/**
 * VM Args: -Xss128k
 */
public class JavaVMStackSOF {
  private int count = 0;
  public static void main(String[] args) {
    new JavaVMStackSOF().method();
  }  
  public void method() {
    System.out.println(++count);
    method();
  }
}

-Xss為128k。其中的一次測(cè)試結(jié)果為,當(dāng)count的值累加到2230時(shí),發(fā)生如下異常:

Exception in thread "main" java.lang.StackOverflowError
at sun.nio.cs.UTF_8.updatePositions(UTF_8.java:77)
at sun.nio.cs.UTF_8$Encoder.encodeArrayLoop(UTF_8.java:564)
at sun.nio.cs.UTF_8$Encoder.encodeLoop(UTF_8.java:619)
at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:561)
at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:271)
at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:125)
at java.io.OutputStreamWriter.write(OutputStreamWriter.java:207)
at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:129)
at java.io.PrintStream.write(PrintStream.java:526)
at java.io.PrintStream.print(PrintStream.java:597)
at java.io.PrintStream.println(PrintStream.java:736)
at com.demo.test.JavaVMStackSOF.method(JavaVMStackSOF.java:15)

隨著-Xss參數(shù)值的增大,可以嵌套的方法調(diào)用層次也相應(yīng)增加。綜上所述,StackOverflowError異常是由于方法調(diào)用的層次太深,最終導(dǎo)致為某個(gè)線程分配的所有棧幀大小總和大于-Xss設(shè)置的值,從而發(fā)生StackOverflowError異常。

(2)OutOfMemoryError異常

java程序代碼啟動(dòng)一個(gè)新線程時(shí),沒(méi)有足夠的內(nèi)存空間為該線程分配java棧(一個(gè)線程java棧的大小由-Xss參數(shù)確定),jvm則拋出OutOfMemoryError異常。例子如下:

package com.demo.test;

/**
 * VM Args: -Xss128k
 */
public class JavaVMStackOOM {

  public static void main(String[] args) {
    int count = 0;
    while (true) {
      Thread thread = new Thread(new Runnable() {
        public void run() {
          while (true) {
            try {
              Thread.sleep(5000);
            } catch (Exception e) {
            }
          }
        }
      });
      thread.start();
      System.out.println(++count);
    }
  }

}

-Xss為128k。其中的一次測(cè)試結(jié)果為,當(dāng)count的值累加到11958時(shí),發(fā)生如下異常:

Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Thread.java:693)
at com.demo.test.JavaVMStackOOM.main(JavaVMStackOOM.java:21)

隨著-Xss參數(shù)值的增大,java程序可以創(chuàng)建的總線程數(shù)越少。

4.所以Server容器啟動(dòng)的時(shí)候我們經(jīng)常關(guān)心和設(shè)置JVM的幾個(gè)參數(shù)如下:

  • -Xms:java Heap初始大小, 默認(rèn)是物理內(nèi)存的1/64。
  • -Xmx:java Heap最大值,不可超過(guò)物理內(nèi)存。
  • -Xmn:young generation的heap大小,一般設(shè)置為Xmx的3、4分之一 。增大年輕代后,將會(huì)減小年老代大小,可以根據(jù)監(jiān)控合理設(shè)置。
  • -Xss:每個(gè)線程的Stack大小,而最佳值應(yīng)該是128K,默認(rèn)值好像是512k。
  • -XX:PermSize:設(shè)定內(nèi)存的永久保存區(qū)初始大小,缺省值為64M。
  • -XX:MaxPermSize:設(shè)定內(nèi)存的永久保存區(qū)最大大小,缺省值為64M。
  • -XX:SurvivorRatio:Eden區(qū)與Survivor區(qū)的大小比值,設(shè)置為8,則兩個(gè)Survivor區(qū)與一個(gè)Eden區(qū)的比值為2:8,一個(gè)Survivor區(qū)占整個(gè)年輕代的1/10。
  • -XX:+UseParallelGC:F年輕代使用并發(fā)收集,而年老代仍舊使用串行收集。
  • -XX:+UseParNewGC:設(shè)置年輕代為并行收集,JDK5.0以上,JVM會(huì)根據(jù)系統(tǒng)配置自行設(shè)置,所無(wú)需再設(shè)置此值。
  • -XX:ParallelGCThreads:并行收集器的線程數(shù),值最好配置與處理器數(shù)目相等 同樣適用于CMS。
  • -XX:+UseParallelOldGC:年老代垃圾收集方式為并行收集(Parallel Compacting)。
  • -XX:MaxGCPauseMillis:每次年輕代垃圾回收的最長(zhǎng)時(shí)間(最大暫停時(shí)間),如果無(wú)法滿足此時(shí)間,JVM會(huì)自動(dòng)調(diào)整年輕代大小,以滿足此值。
  • -XX:+ScavengeBeforeFullGC:Full GC前調(diào)用YGC,默認(rèn)是true。

實(shí)例如:JAVA_OPTS=”-Xms4g -Xmx4g -Xmn1024m -XX:PermSize=320M -XX:MaxPermSize=320m -XX:SurvivorRatio=6″

第一種OutOfMemoryError: PermGen space

發(fā)生這種問(wèn)題的原意是程序中使用了大量的jar或class,使java虛擬機(jī)裝載類的空間不夠,與Permanent Generation space有關(guān)。解決這類問(wèn)題有以下兩種辦法:

1、增加java虛擬機(jī)中的XX:PermSize和XX:MaxPermSize參數(shù)的大小,其中XX:PermSize是初始永久保存區(qū)域大 小,XX:MaxPermSize是最大永久保存區(qū)域大小。如針對(duì)tomcat6.0,在catalina.sh 或catalina.bat文件中一系列環(huán)境變量名說(shuō)明結(jié)束處(大約在70行左右) 增加一行: JAVA_OPTS=" -XX:PermSize=64M -XX:MaxPermSize=128m" 如果是windows服務(wù)器還可以在系統(tǒng)環(huán)境變量中設(shè)置。感覺(jué)用tomcat發(fā)布sprint+struts+hibernate架構(gòu)的程序時(shí)很容易發(fā)生這種內(nèi)存溢出錯(cuò)誤。使用上述方法,我成功解決了部署ssh項(xiàng)目的tomcat服務(wù)器經(jīng)常宕機(jī)的問(wèn)題。

2、清理應(yīng)用程序中web-inf/lib下的jar,如果tomcat部署了多個(gè)應(yīng)用,很多應(yīng)用都使用了相同的jar,可以將共同的jar移到 tomcat共同的lib下,減少類的重復(fù)加載。這種方法是網(wǎng)上部分人推薦的,我沒(méi)試過(guò),但感覺(jué)減少不了太大的空間,最靠譜的還是第一種方法。

第二種OutOfMemoryError: Java heap space

發(fā)生這種問(wèn)題的原因是java虛擬機(jī)創(chuàng)建的對(duì)象太多,在進(jìn)行垃圾回收之間,虛擬機(jī)分配的到堆內(nèi)存空間已經(jīng)用滿了,與Heap space有關(guān)。解決這類問(wèn)題有兩種思路:

1、檢查程序,看是否有死循環(huán)或不必要地重復(fù)創(chuàng)建大量對(duì)象。找到原因后,修改程序和算法。 我以前寫(xiě)一個(gè)使用K-Means文本聚類算法對(duì)幾萬(wàn)條文本記錄(每條記錄的特征向量大約10來(lái)個(gè))進(jìn)行文本聚類時(shí),由于程序細(xì)節(jié)上有問(wèn)題,就導(dǎo)致了 Java heap space的內(nèi)存溢出問(wèn)題,后來(lái)通過(guò)修改程序得到了解決。

2、增加Java虛擬機(jī)中Xms(初始堆大小)和Xmx(最大堆大?。﹨?shù)的大小。如:set JAVA_OPTS= -Xms256m -Xmx1024m

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

相關(guān)文章

  • Java自定義標(biāo)簽用法實(shí)例分析

    Java自定義標(biāo)簽用法實(shí)例分析

    這篇文章主要介紹了Java自定義標(biāo)簽用法,結(jié)合實(shí)例形式分析了java自定義標(biāo)簽的定義、使用方法與相關(guān)注意事項(xiàng),需要的朋友可以參考下
    2017-11-11
  • Vue實(shí)現(xiàn)驗(yàn)證碼登錄的超詳細(xì)步驟

    Vue實(shí)現(xiàn)驗(yàn)證碼登錄的超詳細(xì)步驟

    這篇文章主要給大家介紹了關(guān)于Vue實(shí)現(xiàn)驗(yàn)證碼登錄的超詳細(xì)步驟,我們?cè)谑褂胿ue進(jìn)行前端開(kāi)發(fā)時(shí)都需要登錄驗(yàn)證,文中通過(guò)代碼示例介紹的非常詳細(xì),需要的朋友可以參考下
    2023-09-09
  • maven安裝jar包到本地的操作方法

    maven安裝jar包到本地的操作方法

    這篇文章主要介紹了maven安裝jar包到本地,執(zhí)行該命令后,Maven?會(huì)將該?JAR?文件安裝到你本地?Maven?倉(cāng)庫(kù)中,需要的朋友可以參考下
    2007-01-01
  • Java設(shè)計(jì)模式之java迭代器模式詳解

    Java設(shè)計(jì)模式之java迭代器模式詳解

    這篇文章主要介紹了java迭代器模式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-09-09
  • 使用@Validate分組驗(yàn)證參數(shù)

    使用@Validate分組驗(yàn)證參數(shù)

    SpringFramework的@Validated注解用于方法級(jí)別參數(shù)驗(yàn)證,結(jié)合BeanValidation規(guī)范,支持分組驗(yàn)證,通過(guò)指定驗(yàn)證分組,可以在不同場(chǎng)景下執(zhí)行不同的驗(yàn)證邏輯
    2024-11-11
  • 詳解使用Jenkins自動(dòng)編譯部署web應(yīng)用

    詳解使用Jenkins自動(dòng)編譯部署web應(yīng)用

    本篇主要介紹基于Jenkins實(shí)現(xiàn)持續(xù)集成的方式,通過(guò)案例介紹線上自動(dòng)編譯及部署的配置過(guò)程,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-06-06
  • JAVA學(xué)習(xí)之一步步搭建spring框架

    JAVA學(xué)習(xí)之一步步搭建spring框架

    這篇文章主要介紹了JAVA學(xué)習(xí)之一步步搭建spring框架,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-10-10
  • java實(shí)現(xiàn)Runnable接口適合資源的共享

    java實(shí)現(xiàn)Runnable接口適合資源的共享

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)Runnable接口適合資源的共享,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-07-07
  • 如何使用Java給您的圖片瘦身之Thumbnailator技術(shù)

    如何使用Java給您的圖片瘦身之Thumbnailator技術(shù)

    在java日常開(kāi)發(fā)中經(jīng)常遇到對(duì)圖片資源的操作需求,如壓縮、縮放、旋轉(zhuǎn),下面這篇文章主要給大家介紹了關(guān)于如何使用Java給您的圖片瘦身之Thumbnailator技術(shù)的相關(guān)資料,需要的朋友可以參考下
    2022-10-10
  • Java三種循環(huán)求和方法

    Java三種循環(huán)求和方法

    本篇文章給大家介紹了Java三種循環(huán)求和的方法,大家在學(xué)程序的時(shí)候如果能用的到,參考下吧。
    2018-02-02

最新評(píng)論