亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java內存溢出的幾個區(qū)域總結(注意避坑!)

 更新時間:2022年11月10日 10:55:35   作者:小熊學Java  
內存溢出是指應用系統(tǒng)中存在無法回收的內存或使用的內存過多,最終使得程序運行要用到的內存大于虛擬機能提供的最大內存,下面這篇文章主要給大家介紹了關于Java內存溢出的幾個區(qū)域,總結出來給大家提醒注意避坑,需要的朋友可以參考下

前言

在開發(fā)過程中,時常會遇到內存溢出的問題,有可能是在生產環(huán)境,有的就在開發(fā)中,今天就聊一聊內存溢出。

存在內存的區(qū)域:

  • Java堆溢出
  • 虛擬機棧和本地方法棧溢出
  • 方法區(qū)和運行時常量池溢出
  • 本機內存溢出

1、Java堆溢出

Java堆用于儲存對象實例,我們只要不斷地創(chuàng)建對象,并且保證GC Roots到對象之間有可達路徑來避免垃圾回收機制清除這些對象,那么隨著對象數量的增加,總容量觸及最大堆的容量限制后就會產生內存溢出異常。

1、案例創(chuàng)建

需要手動調節(jié)JVM參數,不然需要等很長時間:-Xms20m -Xmx20m

 public class JavaHeapDemo {
 
     static class OOMObject {
 
     }
     public static void main(String[] args) {
         List<OOMObject> list = new ArrayList<OOMObject>();
         //利用while循環(huán)不斷創(chuàng)建對象
         while (true) {
             list.add(new OOMObject());
         }
     }
 }

2、處理方法

常規(guī)的處理方法是首先通過內存映像分析工具(如Eclipse Memory Analyzer)對Dump出來的堆轉儲快照進行分析

  1. 分清楚到底是出現了內存泄漏(Memory Leak)還是內存溢出(Memory Overflow)
  2. 內存泄漏:通過工具查看泄漏對象到GC Roots的引用鏈,找到泄漏對象是通過怎樣的引用路徑、與哪些GC Roots相關聯,才導致垃圾收集器無法回收它們,根據泄漏對象的類型信息以及它到GC Roots引用鏈的信息,一般可以比較準確地定位到這些對象創(chuàng)建的位置,進而找出產生內存泄漏的代碼的具體位置
  3. 內存溢出:檢查Java虛擬機的堆參數(-Xmx與-Xms)設置,與機器的內存對比,看看是否還有向上調整的空間。再從代碼上檢查 是否存在某些對象生命周期過長、持有狀態(tài)時間過長、存儲結構設計不合理等情況,盡量減少程序運行期的內存消耗

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

關于虛擬機棧和本地方法棧,在《Java虛擬機規(guī)范》中描述了兩種異常:

  • 如果線程請求的棧深度大于虛擬機所允許的最大深度,將拋出StackOverflowError異常。
  • 如果虛擬機的棧內存允許動態(tài)擴展,當擴展棧容量無法申請到足夠的內存時,將拋出OutOfMemoryError異常

《Java虛擬機規(guī)范》明確允許Java虛擬機實現自行選擇是否支持棧的動態(tài)擴展,而HotSpot虛擬機的選擇是不支持擴展,所以除非在創(chuàng)建

線程申請內存時就因無法獲得足夠內存而出現OutOfMemoryError異常,否則在線程運行時是不會因為擴展而導致內存溢出的,只會因為

棧容量無法容納新的棧幀而導致StackOverflowError異常

1、使用-Xss參數減少棧內存容量

 public class JavaVMStackSOF {
 
     private int stackLength = 1;
 
     public void stackLength() {
         stackLength++;
         //無限遞歸
         stackLength();
     }
 
     public static void main(String[] args) {
         JavaVMStackSOF sof = new JavaVMStackSOF();
         try {
             sof.stackLength();
         } catch (Throwable e) {
             System.out.println("stack length:" + sof.stackLength);
             throw e;
         }
     }
 }

這里可以通過指定參數-Xss128k,用來測試棧溢出的情況

3、方法區(qū)和運行時常量池溢出

HotSpot從JDK 7開始逐步“去永久代”的計劃,并在JDK 8中完全使用元空間來代替永久代的背景故事,使用“永久代”還是“元空間”來

實現方法區(qū),對程序有什么實際的影響。

String::intern()是一個本地方法,它的作用是如果字符串常量池中已經包含一個等于此String對象的字符串,則返回代表池中這個字符串的

String對象的引用;否則,會將此String對象包含的字符串添加到常量池中,并且返回此String對象的引用。

這里測試需要JDK6:-XX:PermSize=6M -XX:MaxPermSize=6M

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

JDK8模擬測試

 package jdk8;
 
 import java.io.File;
 import java.lang.management.ClassLoadingMXBean;
 import java.lang.management.ManagementFactory;
 import java.net.URL;
 import java.net.URLClassLoader;
 import java.util.ArrayList;
 import java.util.List;
 
 /**
  *
  * @ClassName:OOMTest
  * @Description:模擬類加載溢出(元空間oom)
  * 為了快速溢出,設置參數:-XX:MetaspaceSize=8m -XX:MaxMetaspaceSize=80m
  * @author diandian.zhang
  */
 public class OOMTest {
     public static void main(String[] args) {
         try {
             //準備url
             URL url = new File("D:/58workplace/11study/src/main/java/jdk8").toURI().toURL();
             URL[] urls = {url};
             //獲取有關類型加載的JMX接口
             ClassLoadingMXBean loadingBean = ManagementFactory.getClassLoadingMXBean();
             //用于緩存類加載器
             List<ClassLoader> classLoaders = new ArrayList<ClassLoader>();
             while (true) {
                 //加載類型并緩存類加載器實例
                 ClassLoader classLoader = new URLClassLoader(urls);
                 classLoaders.add(classLoader);
                 classLoader.loadClass("ClassA");
                 //顯示數量信息(共加載過的類型數目,當前還有效的類型數目,已經被卸載的類型數目)
                 System.out.println("total: " + loadingBean.getTotalLoadedClassCount());
                 System.out.println("active: " + loadingBean.getLoadedClassCount());
                 System.out.println("unloaded: " + loadingBean.getUnloadedClassCount());
             }
         } catch (Exception e) {
             e.printStackTrace();
         }
     }
 }

方法區(qū)溢出也是一種常見的內存溢出異常,一個類如果要被垃圾收集器回收,要達成的條件是比較苛刻的。在經常運行時生成大量動態(tài)類的應用場景里,就應該特別關注這些類的回收狀況。這類場景除了之前提到的程序使用了CGLib字節(jié)碼增強和動態(tài)語言外,常見的還有:大量JSP或動態(tài)產生JSP文件的應用(JSP第一次運行時需要編譯為Java類)、基于OSGi的應用(即使是同一個類文件,被不同的加載器加載也會視為不同的類)等。

在JDK 8以后,永久代便完全退出了歷史舞臺,元空間作為其替代者登場。在默認設置下,前面列舉的那些正常的動態(tài)創(chuàng)建新類型的測試用例已經很難再迫使虛擬機產生方法區(qū)的溢出異常了。不過為了讓使用者有預防實際應用里出現類似于代碼清單2-9那樣的破壞性的操作,HotSpot還是提供了一些參數作為元空間的防御措施,主要包括:

  • -XX:MaxMetaspaceSize:設置元空間最大值,默認是-1,即不限制,或者說只受限于本地內存大小。
  • -XX:MetaspaceSize:指定元空間的初始空間大小,以字節(jié)為單位,達到該值就會觸發(fā)垃圾收集進行類型卸載,同時收集器會對該值進行調整:如果釋放了大量的空間,就適當降低該值;如果釋放了很少的空間,那么在不超過-XX:MaxMetaspaceSize(如果設置了的話)的情況下,適當提高該值。
  • -XX:MinMetaspaceFreeRatio:作用是在垃圾收集之后控制最小的元空間剩余容量的百分比,可減少因為元空間不足導致的垃圾收集的頻率。類似的還有-XX:Max-MetaspaceFreeRatio,用于控制最大的元空間剩余容量的百分比。

4、本機直接內存溢出

直接內存(Direct Memory)的容量大小可通過-XX:MaxDirectMemorySize參數來指定,如果不去指定,則默認與Java堆最大值(由-Xmx指定)一致。

JVM參數:-Xmx20M -XX:MaxDirectMemorySize=10M

 public class DirectMemoryOOM {
     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);
         }
     }
 }

越過了DirectByteBuffer類直接通過反射獲取Unsafe實例進行內存分配(Unsafe類的getUnsafe()方法指定只有引導類加載器才會返回實

例,體現了設計者希望只有虛擬機標準類庫里面的類才能使用Unsafe的功能,在JDK 10時才將Unsafe的部分功能通過VarHandle開放給

外部使用),因為雖然使用DirectByteBuffer分配內存也會拋出內存溢出異常,但它拋出異常時并沒有真正向操作系統(tǒng)申請分配內存,而

是通過計算得知內存無法分配就會在代碼里手動拋出溢出異常,真正申請分配內存的方法是Unsafe::allocateMemory()

總結

到此這篇關于Java內存溢出的幾個區(qū)域的文章就介紹到這了,更多相關Java內存溢出區(qū)域內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java基于socket實現簡易聊天室實例

    Java基于socket實現簡易聊天室實例

    這篇文章主要介紹了Java基于socket實現簡易聊天室的方法,實例分析了java基于socket實現聊天室服務端與客戶端的相關技巧,需要的朋友可以參考下
    2015-05-05
  • springboot使用redis緩存亂碼(key或者value亂碼)的解決

    springboot使用redis緩存亂碼(key或者value亂碼)的解決

    在通過springboot緩存數據的時候,發(fā)現key是一堆很不友好的東西,本文主要介紹了springboot使用redis緩存亂碼(key或者value亂碼)的解決,感興趣的可以了解一下
    2023-11-11
  • 使用Autowired為什么會被IDEA警告最佳修改方法

    使用Autowired為什么會被IDEA警告最佳修改方法

    這篇文章主要介紹了使用Autowired為什么會被IDEA警告,應該怎么修改最佳,除了使用@Autowired以外,我們其實也有幾種好用的方式,使用@Resource替代@Autiwired方法是其中一種,只需要改變一個注解,這里就不展示了,需要的朋友可以參考下
    2023-02-02
  • springboot中.yml文件參數的讀取方式

    springboot中.yml文件參數的讀取方式

    這篇文章主要介紹了springboot中.yml文件參數的讀取方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • 解析阿里GTS開源版本fescar分布式事務

    解析阿里GTS開源版本fescar分布式事務

    這篇文章主要為大家介紹解析阿里GTS開源版本fescar分布式事務的原理及使用說明,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多進步
    2022-02-02
  • SpringMVC DispatcherServlet組件實現解析

    SpringMVC DispatcherServlet組件實現解析

    這篇文章主要介紹了SpringMVC DispatcherServlet組件實現解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-03-03
  • Spring MVC過濾器-登錄過濾的代碼實現

    Spring MVC過濾器-登錄過濾的代碼實現

    本篇文章主要介紹了Spring MVC過濾器-登錄過濾,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧。
    2017-01-01
  • SpringBoot實戰(zhàn):Spring如何找到對應轉換器優(yōu)雅使用枚舉參數

    SpringBoot實戰(zhàn):Spring如何找到對應轉換器優(yōu)雅使用枚舉參數

    這篇文章主要介紹了SpringBoot實戰(zhàn)中Spring是如何找到對應轉換器優(yōu)雅的使用枚舉參數,文中附有詳細的實例代碼有需要的朋友可以參考下,希望可以有所幫助
    2021-08-08
  • Java對時間的簡單操作實例

    Java對時間的簡單操作實例

    這篇文章主要介紹了Java對時間的簡單操作,實例分析了針對java.util.Date的各類常見操作,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-01-01
  • mybatis 查詢sql中in條件用法詳解(foreach)

    mybatis 查詢sql中in條件用法詳解(foreach)

    這篇文章主要介紹了mybatis 查詢sql中in條件用法詳解(foreach),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02

最新評論