日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

JVM(7)内存溢出问题(工作中常用、面试也重要的知识点)

發布時間:2024/3/24 编程问答 58 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JVM(7)内存溢出问题(工作中常用、面试也重要的知识点) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

內存溢出是指應用系統中存在無法回收的內存或使用的內存過多,最終使得程序運行要用到的內存大于虛擬機能提供的最大內存。這篇文章整理自《深入理解java虛擬機》。因為內存溢出問題不僅是工作中的一個重要方面,而且面試中也是經常問。

一、內存溢出原因

內存溢出就是內存不夠,引起內存溢出的原因有很多種,常見的有以下幾種:

1、內存中加載的數據量過于龐大,如一次從數據庫取出過多數據;

2、集合類中有對對象的引用,使用完后未清空,使得JVM不能回收;

3、代碼中存在死循環或循環產生過多重復的對象實體;

4、使用的第三方軟件中的BUG;

5、啟動參數內存值設定的過小;

當然實際情況中內存溢出的原因就太多了。下面我們就對這些原因分類一下:


以上的圖是基于java7來敘述的,從上面這張圖我們能夠得到如下信息:java虛擬機把內存分為5個模塊。

(1)程序計數器:程序計數器是線程私有的,主要的作用是通過改變這個計數器的值來選取下一條需要執行的字節碼指令。既然每個線程都有一個,那么這些線程的計數器是互不影響的。也不會拋出任何異常。

(2)虛擬機棧和本地方法棧:虛擬機棧描述的是java方法執行的內存模型,每個方法在執行的時候都會創建一個棧幀用于存儲局部變量表、操作數棧、動態連接、方法出口等信息。本地方法棧與虛擬機棧的區別是,虛擬機棧為虛擬機執行java方法服務,而本地方法棧則為虛擬機提供native方法服務。

在單線程的操作中,無論是由于棧幀太大,還是虛擬機棧空間太小,當棧空間無法分配時,虛擬機拋出的都是StackOverflowError異常,而不會得到OutOfMemoryError異常。而在多線程環境下,則會拋出OutOfMemoryError異常。

(3)java堆和方法區:java堆區主要存放對象實例和數組等,方法區保存類信息、常量、靜態變量等等。運行時常量池也是方法區的一部分。這兩塊區域是線程共享的區域,只會拋出OutOfMemoryError。

二、內存溢出實例

1、堆溢出

既然堆是存放實例對象的,那我們就無線創建實例對象。這樣堆區遲早會滿。

public class HeapOOM {static class User {}public static void main(String[] args) {List<User> list = new ArrayList<User>();while (true) {list.add(new User());}} } /*Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceededat com.fdd.test.HeapOOM.main(HeapOOM.java:11)*/

因為我提前設置了堆區內存,所以無限創建就會拋出異常。

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

Java虛擬機規范中描述了兩種異常:

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

第一種我們只需要使用方法遞歸調用即可模擬:

public class StackOutOfMemoryError {public static void main(String[] args) { test();}private static void go() {System.out.println("StackOverflowError異常");test();} } /*Exception in thread "main" java.lang.StackOverflowErrorat sun.nio.cs.ext.DoubleByte$Encoder.encodeLoop(DoubleByte.java:617)at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:579)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.fdd.test.StackOutOfMemoryError.go(StackOutOfMemoryError.java:11)at com.fdd.test.StackOutOfMemoryError.go(StackOutOfMemoryError.java:13)*/

第二種也可以遞歸調用模擬,,但是使用的是類直接調用。

public class JavaVMStackSOF {private int stackLength = 1;public void stackLeak() {stackLength++;stackLeak();}public static void main(String[] args) {JavaVMStackSOF oom = new JavaVMStackSOF();oom.stackLeak();} } /*Exception in thread "main" java.lang.StackOverflowErrorat com.lindaxuan.outofmemory.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:18)at com.lindaxuan.outofmemory.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:19)at com.lindaxuan.outofmemory.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:19)at com.lindaxuan.outofmemory.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:19)at com.lindaxuan.outofmemory.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:19)at com.lindaxuan.outofmemory.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:19)at com.lindaxuan.outofmemory.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:19)at com.lindaxuan.outofmemory.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:19)at com.lindaxuan.outofmemory.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:19)... */

3、方法區和運行時常量池溢出

public class JavaMethodAreaOOM {public static void main(String[] args) {while (true) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(User.class);enhancer.setUseCache(false);enhancer.setCallback(new MethodInterceptor() {public Object intercept(Object obj, Method method,Object[] args, MethodProxy proxy) throws Throwable {return proxy.invokeSuper(obj, args);}});enhancer.create();}}static class User {} } /*Exception in thread "main"Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "main" */

4、本機直接內存溢出

DirectMemory容量可通過-XX: MaxDirectMemorySize指定,如果不指定,則默認與Java堆最大值 (-Xmx指定)一樣。

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);}} }

上面介紹了幾個實例,那遇到這種問題如何排查呢?

三、內存溢出排查

排查其實最主要的就是檢查代碼,而且內存溢出往往都是代碼的問題。當然一下幾點都是需要注意的:

(1)內存中加載的數據量過于龐大,如一次從數據庫取出過多數據;

(2)集合類中有對對象的引用,使用完后未清空,使得JVM不能回收;

(3)代碼中存在死循環或循環產生過多重復的對象實體;

(4)使用的第三方軟件中的BUG;

(5)啟動參數內存值設定的過小;

最后就是解決了。

第一步,修改JVM啟動參數,直接增加內存。

第二步,檢查錯誤日志

第三步,對代碼進行走查和分析,找出可能發生內存溢出的位置。

一般情況下代碼出錯的概率會比較大一些,當然了不同的場景不同錯誤總是復雜多樣的。

(4)使用的第三方軟件中的BUG;

(5)啟動參數內存值設定的過小;

最后就是解決了。

第一步,修改JVM啟動參數,直接增加內存。

第二步,檢查錯誤日志

第三步,對代碼進行走查和分析,找出可能發生內存溢出的位置。

一般情況下代碼出錯的概率會比較大一些,當然了不同的場景不同錯誤總是復雜多樣的。

**

喜歡的可以關注我的公眾號:java的架構師技術棧,獲取更多文章和教程資源

**

總結

以上是生活随笔為你收集整理的JVM(7)内存溢出问题(工作中常用、面试也重要的知识点)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。