JAVA內存溢出
JAVA的內存分為方法區、虛擬機棧、本地方法棧、堆、程序計數器五個部分,除程序計數器外,其它部分都可能出現內存溢出OOM(OutOfMemeryError)。
1、內存溢出和內存泄漏的區別
內存溢出 (Out Of Memory):是指程序在申請內存時,沒有足夠的內存空間供其使用,出現Out Of Memory。
內存泄露 (Memory Leak):是指程序在申請內存後,由於某種原因無法釋放已申請的內存空間,導致這塊內存無法再次被利用,造成系統內存的浪費。一次內存泄露危害可以忽略,但內存泄露堆積的後果很嚴重,無論多少內存,遲早會被占光。
2、內存溢出詳解
2.1.Java虛擬機棧與本地方法棧
每個線程棧的大小控制參數時 -Xss。
Java虛擬機在棧中定義了兩種異常,StrackOverFlowError和OutOfMemoryError:unable to create new native thread。當請求棧的深度大於java虛擬機所允許的最大深度則拋出StrackOverFlowError;如果Java虛擬機在棧擴展時,沒有申請到足夠的空間時,則拋出OutOfMemoryError:unable to create new native thread。
StrackOverFlowError:單線程內占用內存超過了棧的大小-Xss
出現場景
一、局部數組或集合過大。一般出現在大查詢或大導出的情況下。
二、方法調用太多。一般出現在遞歸調用層次太多或死循環時。
三、指針或數組越界。這種情況最常見,例如進行字符串拷貝,或處理用戶輸入等等。
解決方式
優化程序、減少方式的調用、增大-Xss參數
OutOfMemoryError:unable to create new native thread:多線程占用的內存超過了可用內存(進程可用內存(32位操作系統時為2G)-Xmx-MaxPermSize-虛擬機本身耗費的內存和程序計數器使用的內存)
解決方式
減少線程數量、降低-Xss的大小(即減少每個線程擁有的內存大小)、降低-Xmx以及MaxPermSize的大小擴大留給棧的空間
2.方法區內存溢出
方法區的大小通過-PermSize和-MaxPermSize控制。
當持久帶溢出的時候拋出 java.lang.OutOfMemoryError: PermGen space
因為類常量和運行時常量也存儲在方法區中,所以運行時常量過多也可導致方法區的OOM,但是沒有直接控制常量池大小的參數,只能通過-PermSize和-MaxPermSize來間接控制。
出現場景
一、在Spring以及Hibernate,Mybatis中都會使用GeneratedConstructorAccessor、動態代理以及CGLib字節碼增強技術的等動態生成類,那麽就需要強大的方法區來支撐。
二、運行時常量池溢出
三、使用一些應用服務器的熱部署的時候,我們就會遇到熱部署幾次以後發現內存溢出了,這種情況就是因為每次熱部署的後,原來的Class沒有被卸載掉。
解決方式
一、增加java虛擬機中的XX:PermSize和XX:MaxPermSize參數的大小,其中XX:PermSize是初始永久保存區域大小,XX:MaxPermSize是最大永久保存區域大小。如針對tomcat6.0,在catalina.sh 或catalina.bat文件中一系列環境變量名說明結束處(大約在70行左右) 增加一行:
JAVA_OPTS=" -XX:PermSize=64M -XX:MaxPermSize=128m"
如果是windows服務器還可以在系統環境變量中設置。感覺用tomcat發布sprint+struts+hibernate架構的程序時很容易發生這種內存溢出錯誤。使用上述方法,我成功解決了部署ssh項目的tomcat服務器經常宕機的問題。
二、清理應用程序中web-inf/lib下的jar,如果tomcat部署了多個應用,很多應用都使用了相同的jar,可以將共同的jar移到tomcat共同的lib下,減少類的重復加載。這種方法是網上部分人推薦的,我沒試過,但感覺減少不了太大的空間,最靠譜的還是第一種方法。
3.堆內存溢出
堆的大小通過-Xms和-Xmx設置
堆內存溢出的時候,虛擬機會拋出 java.lang.OutOfMemoryError:java heap space
出現場景
創建對象時如果沒有可以分配的堆內存,JVM就會拋出OutOfMemoryError:java heap space異常
解決方式
首先需要分清是內存溢出還是內存泄露
(1)如果是內存溢出,則通過 調大 -Xms,-Xmx參數。
(2)如果是內存泄露,則看對象如何被 GC Root 引用。
出現此種情況的時候,我們需要根據內存溢出的時候產生的 dump 文件來具體分析(需要增加 -XX:+HeapDump
OnOutOfMemoryError jvm啟動參數)。出現此種問題的時候有可能是內存泄漏,也有可能是內存溢出了。
1、配置方法
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${目錄}。
2、參數說明
(1)-XX:+HeapDumpOnOutOfMemoryError參數表示當JVM發生OOM時,自動生成DUMP文件。
(2)-XX:HeapDumpPath=${目錄}參數表示生成DUMP文件的路徑,也可以指定文件名稱,例如:-XX:HeapDu
mpPath=${目錄}/java_heapdump.hprof。如果不指定文件名,默認為:java_<pid><date><time>_heapDu
mp.hprof。
如果是內存泄漏,我們要找出內存泄漏的對象是怎麽被GC ROOT引用起來,然後通過引用鏈來具體分析泄露的
原因。
如果出現了內存溢出問題,這往往是程序本生需要的內存大於了我們給虛擬機配置的內存,這種情況下,我
們可以采用調大-Xmx來解決這種問題。
JAVA內存溢出