Java中的OutOfMemoryError
轉載自??Java中的OutOfMemoryError
引子:今天在<Sharding-JDBC官方群>里有個哥們稱“不連sjdbc不會把內存吃光,連sjdbc跑一會就把內存吃光”,倍感詫異,我們已經用sj很久了,一直未發現sj吃內存的情況,遂向他要了測試程序。測試之后才發現他所謂的吃內存是報了“java.lang.OutOfMemoryError: unable to create new native thread”的錯,殊不知創建線程不使用JVM Memory,這個報錯不是程序吃內存,跟sjdbc更是沒有關系。他的數據庫連接池maxActive=30,開線程較多時(我開了10000個),前面的線程沒有釋放數據庫連接,后面的線程就要等待,造成線程積壓,最終無法創建新線程,自然“unable to create new native thread”。所以還需要掃盲式的向諸位普及一下Java中的內存溢出。
1.java.lang.OutOfMemoryError: unable to create new native thread
就是上面例子里面提到的情況。Java中當你創建線程的時候,JVM會在JVM 內存創建一個Thread同時創建一個系統本地線程,這個系統線程使用的內存不是JVM memory,而是系統剩余的內存,所以遇到這種情況有時候需要通過“減少內存”的手段來解決(指減少堆內存)。通常情況下我們有個計算公式來估算能創建線程數的多少:countOfThreads=(processMaxMemory - JVM Memory - otherOsMemory) / (threadStackSize)?,這里的MaxProcessMemory是指一個進程可以占用的最大內存,比如在32位window下是2G,otherOsMemory是保留的操作系統內存,threadStackSize是通過-Xss參數設置的線程棧大小,當然,還會受到系統最大可創建的線程數量的限制。
2.Java.lang.OutOfMemoryError: Java heap space
這種是我們最常見的Java堆溢出,我們配置JVM參數時使用-Xms配置堆的最小值,使用-Xmx配置堆的最大值(通常會將-Xms和-Xmx配置成相同,避免堆的自動擴展)。Java堆中存放的是對象實例,當Java堆中對象達到限制就會產生內存溢出,常見的情況有:死循環往一個List中添加對象,一次性將大文件或者從數據庫查詢的大批量數據加載到內存中。對于這種情況,我們通過JVM配置-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/Data/domains/trans-account/server1/logs來保存內存快照,然后用相關內存分析工具進行分析。
3.?java.lang.OutOfMemoryError: PermGen space
?PermGen space的全稱是Permanent Generation space,是內存的永久保存區域,主要存儲虛擬機加載的類、常量、靜態變量等元數據信息,垃圾收集行為在這個區域幾乎不出現。對于有大量JSP、大量使用CGLib字節碼增強的應用,會很容易出現這種錯誤,出現問題時,我們經常通過增大-XX:MaxPermSize參數來解決。
4.?java.lang.OutOfMemoryError: GC overhead limit exceeded
GC overhead limt exceed檢查是Hotspot VM定義的一個策略,通過統計GC時間來預測是否要OOM了,提前拋出異常,防止OOM發生。官方對此的定義是:“并行/并發回收器在GC回收時間過長時會拋出OutOfMemroyError。過長的定義是,超過98%的時間用來做GC并且回收了不到2%的堆內存。用來避免內存過小造成應用不能正常工作。”這種情況跟第二種情況有重合的地方,也是通過檢查是否有死循環或者占用大內存的代碼,當然,可以使用-XX:-UseGCOverheadLimit(默認是+UseGCOverheadLimit)來去除GC時間的限制。
5.?java.lang.OutOfMemoryError: nativeGetNewTLA
這個錯誤只有在JRockit的JVM上才會遇到,大家工作環境中如果都默認使用Hotspot的話應該不會遇到這個問題,所以如果大家不感興趣完全可以不care(真的,私以為,沒有業務場景基礎的技術意淫都是耍流氓)。TLA是Thread Local Area(線程本地空間)的簡寫,線程本地空間是多線程程序里面為了更有效的進行內存分配而建立的緩存。每一個線程都有一份自己的緩存,當這個線程要創建對象的時候,就在這上面分配。如果你有很多線程同時并發,又要創建大量的對象,可能會出現這個問題。
6.java.lang.OutOfMemoryError: Requested array size exceeds VM limit?
這個錯誤比較少見,除非你真的new了一個非常非常大的數組(比如,一個億?YOU CAN TRY~)當出現這種情況,與其去增大JVM的-Xmx,不如好好看下你的代碼邏輯是不是出現了什么問題。
7.java.lang.OutOfMemoryError: request xxxxxx(size) bytes for xxxxxxx(reason). Out of swap space??
額,這種情況我真沒遇到過,不過我們可以了解一下:它是當虛擬機向本地操作系統申請內存失敗時拋出的。這和你用完了堆或者持久化中的內存的情況有些不同。這個錯誤通常是在你的程序已經逼近平臺限制的時候產生的。這個信息告訴你的是你可能已經用光了物理內存以及虛擬內存了。由于虛擬內存通常是用磁盤作為交換分區,因此你最先想到的解決方法可能是先增加交換分區的大小。
8.java.lang.OutOfMemoryError: xxxx<reason> xxxx<stack trace>(Native method)
這種報錯是從native method中拋出的,不是JVM執行的方法,如果遇到這種情況,咳,自求多福吧。
總結
以上是生活随笔為你收集整理的Java中的OutOfMemoryError的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何合理的规划一次 JVM 性能调优
- 下一篇: 2017年电脑配置(2017配置电脑)