簡體   English   中英

當 JVM 在運行時分配完 memory 時會發生什么?

[英]What happens when the JVM runs out of memory to allocate during run time?

在考慮了很長時間提出這個問題的通用方法(但沒有找到)之后,我只是想把它作為一個具體的例子來問:

假設我有一台 Linux 機器,它有 1 Gb 的 memory 可以分配給進程(物理和交換總計 1 Gb)。

我在機器上安裝了一個標准的 Oracle 熱點 JVM 版本 7。 如果在給定的時刻,有足夠多的程序在運行,以至於 1 Gb 中只有 400 Mb 是空閑的,我會在那個時刻啟動一個 Java 程序,並帶有以下 JVM 標志:

java -Xms256m -Xmx512m -jar myJar.jar

發生了什么事? :

A. JVM 是否無法立即啟動,因為它會嘗試分配 memory 的所有 512 Mb 並失敗(因為目前沒有足夠的可用 memory)?

如果 JVM 啟動:

如果在某個時候運行的 Java 進程需要超過 400 Mb 的 memory(除了當前 Java 進程已經使用的空間之外,仍然只有 400 Mb 的 memory 是免費的),將會發生什么:

B. Java 進程會因 OutOfMemroyError 而失敗嗎?

C。它會因其他(標准)錯誤而失敗嗎?

D. 是未定義的行為嗎?

-Xmx只定義堆的最大大小。 它不能保證有這么多的記憶。 它只能確保堆永遠不會比給定值大。 也就是說,選項B。將會發生,將拋出outOfMemoryError。

假設我有一台具有1 Gb內存的Linux機器,它可以分配給進程(物理和交換總數為1 Gb)。

我的第一反應是,除非你在談論手機,否則我會得到更多的記憶。 您可以以低於100美元的價格購買16 GB(b =位,B =字節)。

JVM是否無法立即啟動,因為它將嘗試分配所有512 Mb的內存並失敗(由於目前沒有足夠的可用內存)?

如果您的系統沒有512 MB(加上一些開銷),因為它在啟動時分配用於堆的連續虛擬內存,則會發生這種情況。

即使你有550 MB空閑,程序也可能無法啟動,因為它需要加載的不僅僅是堆。

Java進程是否會因OutOfMemoryError而失敗?

如果您的程序在運行時使用512 MB,則無論您的計算機具有多少內存,都會發生這種情況。 只有在JVM啟動后才會出現此錯誤。 如果無法啟動,您將不會收到此錯誤。

它會因一些其他(標准)錯誤而失敗嗎?

如果在程序啟動后耗盡交換空間,則可以執行此操作。 這是罕見的,只發生在嚴重超載的機器上。 我所看到的是由於低級操作系統無法分配內存而導致JVM崩潰。

Java 6 Update 25 VM崩潰:內存不足

當Java虛擬機無法分配對象時, OutOfMemroyError“拋出,因為內存不足,垃圾收集器無法再提供更多內存。”

所以,實質上, “B. Java進程因OutOfMemroyError失敗”

如果你有太多的占用內存以至於可用空間甚至無法支持空閑JVM,那么你會得到一些錯誤,說程序沒有足夠的內存,或者JVM會崩潰。

如果可以運行JVM,則可以使用-Xmx指定堆空間限制。 這並不意味着JVM在啟動時將分配所有堆 - 它只是一個內部限制。 如果JVM想要增加堆空間,但沒有足夠的內存,或者您需要的堆比-Xmx指定的堆多,那么在當前運行的Java程序中會出現OutOfMemoryError。

在非常極端的情況下,在JVM運行時可能會耗盡可用內存,同時JVM需要更多內存用於其內部操作(而不是堆空間) - 然后JVM會告訴您它需要更多內存,但是無法得到任何東西,並且終止,否則它將徹底崩潰。

JVM進程將在虛擬內存中運行,因此運行的其他進程的分配問題是相關的,但不是完全確定的。

當JVM無法分配更多內存(無論出於何種原因)時,進程本身不會終止,而是開始 JVM中拋出OutOfMemoryError ,但不在JVM外部OutOfMemoryError 換句話說,JVM繼續運行,但JVM中運行的程序通常會失敗,因為大多數程序都不能充分處理低內存條件。 在這種相當常見的情況下,當程序沒有做任何事情來處理錯誤時,JVM將終止程序並退出。 最終,這是來自內存分配,但不是直接的。 一段代碼可以在低內存條件下自行擴展並繼續運行。

其他人已經指出,有時JVM本身並不能很好地處理低內存,但這是一個相當極端的條件。

盡管這個問題已有 10 年歷史,但我今天還在考慮這個問題,並決定實際嘗試一下。 :-)

  • Linux 版本 Linux 版本 5.10.0-0.bpo.9-amd64
  • JVM 版本 OpenJDK 運行環境 (build 11.0.14+9-post-Debian-1deb10u1)

使用這個小測試程序:

import java.util.*;

public class OOMTest {
    public static void main(String... atgs){
        var list = new ArrayList<String>();
        while(true){
            list.add(new String("abc"));
        }
    }
}

在具有 4G RAM 和 4G 交換空間的機器上(這只是我的 NAS:-)):

tomi@unyanas:~/workspace$ free -h
              total        used        free      shared  buff/cache   available
Mem:          3.7Gi       980Mi       2.4Gi        27Mi       355Mi       2.4Gi
Swap:         3.7Gi       2.2Gi       1.5Gi
  • 在允許 1G 堆的情況下運行時,進程會因 OOM 而終止:
tomi@unyanas:~/workspace$ java -Xmx1G OOMTest
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at OOMTest.main(OOMTest.java:9)
  • 當允許 10G 堆運行時,則:
    • 該過程如上所述開始,盡管機器中根本沒有那么多 RAM+swap
    • 但是 output 顯然不是 OOM,進程只是被 kernel 殺死:
tomi@unyanas:~/workspace$ java -Xmx10G OOMTest
Killed

所以總結一下:

  • 當主機內存不足時得到 OOM 至少不能保證(我在 3 次嘗試中有 3 次得到這個結果)
  • 允許使用 -Xmx “過度使用”機器容量
  • 似乎只有當進程的“上限”是 -Xmx 值(默認值或明確指定)時才能保證獲得 OOM,否則會有更多免費 memory(RAM + swap ) 留給操作系統

對於上述情況,可以說這種情況是由於測試代碼具有 infinit memory 占用空間這一事實造成的,所以我也想嘗試一個具有高生成率的進程,否則 finit memory 占用空間可以通過設置-Xmx 值太高。 因此,如果 GC 可以被愚弄,相信可用的 memory 比實際多得多,並最終被殺死,或者如果 kernel 通知它失敗的 OS 級別 memory 分配並因此限制堆大小。 答案是它可以被愚弄。

我已經像這樣更改了上面的代碼:

import java.util.*;

public class OOMTest {
    public static void main(String... atgs){
        var list = new ArrayList<String>();
        while(true){
            list.add(new String("abc"));
            if (list.size() > 50000000){
                list.remove(list.size() - 1);
            }
        }
    }
}

當指定機器可以處理的 -Xmx 值時,程序可以運行很長時間(好吧,我真的讓它運行只要我吃晚飯,但你明白了:-))

所以這永遠不會退出(當啟用 GC 日志記錄時,一旦達到 2G 堆大小,就可以觀察到一個很好的重復模式):

java -Xmx2G OOMTest

但是當使用 Xmx10G 運行時,進程再次被殺死,沒有 OOM:

tomi@unyanas:~/workspace$ java -Xmx10G OOMTest
Killed

這表明,當 JVM 嘗試分配比主機上當前可用的更多 memory 作為 RAM+swap 時,它獲得的唯一“建設性反饋”類似於 kill -9。 因此,通過使用過高的 -Xmx 值,可以使 function 正確的進程失敗。 這絕不是說這會發生在所有 OS-es、JVM 實現上,甚至只是 GC 算法(我使用的是默認 G1),但這絕對是上述設置的情況。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM