最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JAVA?OOM內(nèi)存溢出問題深入解析

 更新時間:2023年10月07日 15:53:46   作者:兩年  
這篇文章主要為大家介紹了JAVA?OOM內(nèi)存溢出問題深入解析,在生產(chǎn)環(huán)境搶修中,我們經(jīng)常會碰到應用系統(tǒng)java內(nèi)存OOM的情況,這個問題非常常見,今天我們就這個問題來深入學習探討一下

JAVA內(nèi)存OOM溢出的幾種常見業(yè)務場景

當生產(chǎn)系統(tǒng)遇到莫種場景時就會觸發(fā)OOM內(nèi)存溢出,導致系統(tǒng)不可用。常見的場景如:

  • 秒殺活動:當大量的請求進來的時候,導致系統(tǒng)瞬間創(chuàng)建大量的內(nèi)存對象,如果內(nèi)存對象都是大對象而且不能及時釋放,就會撐爆內(nèi)存
  • 特殊業(yè)務場景:如獲取報表數(shù)據(jù),報表信息需要從數(shù)據(jù)庫中查詢大量的數(shù)據(jù)到內(nèi)存中進行處理,如果對數(shù)據(jù)沒有控制的話,就會撐爆內(nèi)存
  • 內(nèi)存空間分配過小:如tomcat類的web容器分配的java內(nèi)存空間過小,當過多的線程創(chuàng)建的對象直接把內(nèi)存用完
  • 創(chuàng)建的類過多,導致永久代或者元空間被消耗光

JAVA內(nèi)存結構原理

  • 類的加載

  • 編寫好的java文件通過IDE編譯,變成.class二進制字節(jié)文件
  • 該字節(jié)文件加載進類加載器

詳細過程如下,java程序運行時,虛擬機會單獨劃分出一塊內(nèi)存區(qū)域,我們需要特別關注堆和棧這兩塊區(qū)域,生產(chǎn)搶修頻繁出問題的也是這兩個區(qū)域。(堆負責數(shù)據(jù)存儲,棧則負責程序運行

  • JAVA 堆

Java 堆區(qū)還可以劃分為新生代和老年代,新生代又可以進一步劃分為 Eden 區(qū)、Survivor 1 區(qū)、Survivor 2 區(qū)。

該區(qū)域的主要特點:

  • 該區(qū)域是程序的數(shù)據(jù)存儲區(qū)域,主要負責存放new對象,但不存放數(shù)據(jù)類型和對象引用
  • 該區(qū)域是垃圾回收的主要工作區(qū)域
  • JAVA棧

存放基本數(shù)據(jù)類型(boolean、byte、char、short、int、float、long、double)以及對象的引用(它可能是一個指向?qū)ο笃鹗嫉刂返囊弥羔槪部赡苤赶蛞粋€代表對象的句柄或者其他與此對象相關的位置)。

這個區(qū)域可能有兩種異常:如果線程請求的棧深度大于虛擬機所允許的深度,將拋出 StackOverflowError 異常;如果虛擬機??梢詣討B(tài)擴,當擴展時無法申請到足夠的內(nèi)存時會拋出 OutOfMemoryError異常。

設計程序演示內(nèi)存溢出現(xiàn)象

為了更好的理解程序是如何運行,并導致JAVA內(nèi)存溢出的,我設計了四個場景來進行模擬演示

  • 棧溢出(StackOverflowError)
  • 堆溢出(OutOfMemoryError:Java heap space)
  • 永久代溢出 java8之前版本(OutOfMemoryError: PermGen space)。java8之后(包含)版本(OutOfMemoryError: PermGen space)
  • 直接內(nèi)存溢出
  • 棧溢出(StackOverflowError)

線程請求的棧深度大于虛擬機所允許的深度,將拋出 StackOverflowError 異常

/**
 * 棧溢出
 */
public class Stack {
    public static void main(String[] args) {
        new Stack().test();
    }
    public void test() {
        test();
    }
}

棧深度被消耗殆盡拋出異常

Exception in thread "main" java.lang.StackOverflowError
        at Stack.test(Stack.java:11)
        at Stack.test(Stack.java:11)
        at Stack.test(Stack.java:11)

  • 堆溢出(OutOfMemoryError:Java heap space)

通過不斷的往數(shù)組列表中存放大對象,最終把內(nèi)存資源消耗殆盡

import java.util.ArrayList;
import java.util.List;
public class HeapOOMTest {
    public static void main(String[] args) {
        List<byte[]> list = new ArrayList<>();
        try {
            while (true) {
                // 分配大量的內(nèi)存,每次分配1MB的字節(jié)數(shù)組
                byte[] data = new byte[1024 * 1024]; // 1MB
                list.add(data);
            }
        } catch (OutOfMemoryError e) {
            System.out.println("發(fā)生堆溢出錯誤:Java heap space");
            e.printStackTrace();
        }
    }
}

拋出異常

發(fā)生堆溢出錯誤:Java heap space
java.lang.OutOfMemoryError: Java heap space
        at HeapOOMTest.main(HeapOOMTest.java:11)

  • 永久代溢出 java8之前版本(OutOfMemoryError: PermGen space)。java8之后(包含)版本(OutOfMemoryError: Metaspace)

java1.8之后就舍棄了永久代,取而代之的是元空間。我的環(huán)境是jdk1.8,所以只能演示元空間的報錯。

這段Java代碼演示了如何在Java程序中觸發(fā)"OutOfMemoryError: Metaspace"錯誤。它通過不斷生成新的類、加載這些類并將其加入到列表中,最終導致"Metaspace"區(qū)域的內(nèi)存耗盡。

具體流程如下:

  • main方法中,通過ArrayList創(chuàng)建一個classes列表,用于存儲動態(tài)生成的類。
  • while(true)循環(huán)中,程序不斷執(zhí)行以下操作:

    • 生成一個唯一的類名("DynamicClass" + 當前納秒時間戳)。
    • 使用generateClassBytes方法生成類的字節(jié)碼。
    • 將生成的字節(jié)碼寫入到以類名命名的文件中。
    • 使用自定義的CustomClassLoader類加載器加載這個類。
    • 將加載后的類對象添加到classes列表中。
    • 可選地,刪除已經(jīng)加載的類文件,釋放磁盤空間。
  • 當"Metaspace"區(qū)域的內(nèi)存耗盡時,會拋出"OutOfMemoryError: Metaspace"異常,程序捕獲并打印異常信息。
import java.util.List;
import java.util.ArrayList;
import java.nio.file.*;
import java.io.IOException;
public class PermGenOutOfMemory {
    public static void main(String[] args) {
        List<Class<?>> classes = new ArrayList<>();
        try {
            while (true) {
                // Generate a unique class name and bytecode
                String className = "DynamicClass" + System.nanoTime();
                byte[] classData = generateClassBytes(className);
                // Define the class by writing it to a file and loading it
                Path classFilePath = Paths.get(className + ".class");
                Files.write(classFilePath, classData);
                Class<?> clazz = loadClass(className, classFilePath);
                classes.add(clazz);
                // Optional: Delete the class file after loading
                Files.delete(classFilePath);
            }
        } catch (OutOfMemoryError | IOException e) {
            System.out.println("OutOfMemoryError: Metaspace");
            e.printStackTrace();
        }
    }
    static byte[] generateClassBytes(String className) {
        // Replace this with your own class bytecode generation logic
        // You can use libraries like ASM for bytecode generation
        // For simplicity, let's just create a class with a single method
        String classContent = "public class " + className + " { public void doSomething() { System.out.println(\"Hello from " + className + "\"); } }";
        return classContent.getBytes();
    }
    static Class<?> loadClass(String className, Path classFilePath) throws IOException {
        // Load the class from the file into the Metaspace
        byte[] classData = Files.readAllBytes(classFilePath);
        return new CustomClassLoader().loadClass(className, classData);
    }
    static class CustomClassLoader extends ClassLoader {
        public Class<?> loadClass(String name, byte[] classData) {
            return defineClass(name, classData, 0, classData.length);
        }
    }
}
  • 直接內(nèi)存溢出

分配 1MB 的直接內(nèi)存并將其累加到 allocatedMemory 中,使用 unsafe.allocateMemory(memory) 分配直接內(nèi)存。

如果在分配直接內(nèi)存時發(fā)生異常,則會捕獲異常并打印異常堆棧信息。

import sun.misc.Unsafe;
import java.lang.reflect.Field;
public class DirectMemoryOOMTest {
    public static void main(String[] args) {
        int i = 0;
        long allocatedMemory = 0;
        Unsafe unsafe = null;
        try {
            Field field = Unsafe.class.getDeclaredFields()[0];
            field.setAccessible(true);
            unsafe = (Unsafe) field.get(null);
            while (true) {
                long memory = 1024 * 1024;
                allocatedMemory += memory;
                unsafe.allocateMemory(memory);
                i++;
            }
        } catch (Exception e) {
            e.printStackTrace();
         } 
    }
}

Exception in thread "main" java.lang.OutOfMemoryError
        at sun.misc.Unsafe.allocateMemory(Native Method)
        at DirectMemoryOOMTest.main(DirectMemoryOOMTest.java:19)
PS D:\java>

總結

  • 了解了java內(nèi)存結構原理和生產(chǎn)主要發(fā)生問題的區(qū)域
  • 了解了哪些業(yè)務場景會導致的OOM
  • 通過代碼演示了幾種導致OOM問題的情況

以上就是JAVA內(nèi)存溢出問題深入解析的詳細內(nèi)容,更多關于JAVA 內(nèi)存溢出的資料請關注腳本之家其它相關文章!

相關文章

  • springBoot中的properties配置解析

    springBoot中的properties配置解析

    這篇文章主要介紹了springBoot中的properties配置解析,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Java Math類的三個方法ceil,floor,round用法

    Java Math類的三個方法ceil,floor,round用法

    這篇文章主要介紹了Java Math類的三個方法ceil,floor,round用法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Spring?myBatis數(shù)據(jù)庫連接異常問題及解決

    Spring?myBatis數(shù)據(jù)庫連接異常問題及解決

    這篇文章主要介紹了Spring?myBatis數(shù)據(jù)庫連接異常問題及解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • Java并發(fā)系列之AbstractQueuedSynchronizer源碼分析(概要分析)

    Java并發(fā)系列之AbstractQueuedSynchronizer源碼分析(概要分析)

    這篇文章主要為大家詳細介紹了Java并發(fā)系列之AbstractQueuedSynchronizer源碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-02-02
  • Java中利用gson解析Json實例教程

    Java中利用gson解析Json實例教程

    這篇文章主要給大家介紹了關于Java中利用gson解析Json 的相關資料,文中給出了詳細的示例代碼供大家參考學習,相信對大家具有一定的參考學習價值,需要的朋友們下面來一起看看吧。
    2017-05-05
  • springboot項目中統(tǒng)一時間格式處理方法

    springboot項目中統(tǒng)一時間格式處理方法

    JacksonConfiguration主要用于配置JSON的序列化和反序列化,而LocalDateTimeFormatter則用于處理請求和響應中的LocalDateTime格式,這兩個配置項在SpringBoot項目中至關重要,確保數(shù)據(jù)格式的正確處理和傳輸
    2024-10-10
  • Java computeIfAbsent()方法使用小結

    Java computeIfAbsent()方法使用小結

    本文主要介紹了Java computeIfAbsent()方法使用小結,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2025-12-12
  • java 和 json 對象間轉換

    java 和 json 對象間轉換

    這篇文章主要介紹了java 和 json 對象間轉換,需要的朋友可以參考下
    2014-03-03
  • 淺談JAVA字符串匹配算法indexOf函數(shù)的實現(xiàn)方法

    淺談JAVA字符串匹配算法indexOf函數(shù)的實現(xiàn)方法

    這篇文章主要介紹了淺談字符串匹配算法indexOf函數(shù)的實現(xiàn)方法,indexOf函數(shù)我們可以查找一個字符串(模式串)是否在另一個字符串(主串)出現(xiàn)過。對此感興趣的可以來了解一下
    2020-07-07
  • SpringBoot多線程進行異步請求的處理方式

    SpringBoot多線程進行異步請求的處理方式

    這篇文章主要介紹了SpringBoot多線程進行異步請求的處理方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜
    2021-12-12

最新評論

宁南县| 彰化县| 福贡县| 五大连池市| 景谷| 日土县| 江川县| 得荣县| 城步| 思南县| 呈贡县| 镇沅| 新建县| 临高县| 怀集县| 阿尔山市| 建平县| 都匀市| 旬邑县| 垫江县| 吉林省| 吉安县| 深水埗区| 江山市| 都昌县| 巴中市| 邓州市| 宁化县| 昭觉县| 项城市| 托克逊县| 台南县| 壤塘县| 通城县| 江口县| 潼南县| 珲春市| 万盛区| 宁陵县| 罗江县| 汽车|