简体   繁体   English

当 JVM 在运行时分配完 memory 时会发生什么?

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

After thinking for a long time of a generic way to pose this question (and failing to find one) I'm just going to ask it as a concrete example:在考虑了很长时间提出这个问题的通用方法(但没有找到)之后,我只是想把它作为一个具体的例子来问:

Suppose I have a Linux machine which has 1 Gb of memory which it can allocate to processes (physical and swap totals 1 Gb).假设我有一台 Linux 机器,它有 1 Gb 的 memory 可以分配给进程(物理和交换总计 1 Gb)。

I have a standard Oracle Hotspot JVM version 7 installed on the machine.我在机器上安装了一个标准的 Oracle 热点 JVM 版本 7。 If at a given moment, there are enough programs running such that only 400 Mb of that 1 Gb are free, and I start a Java program at that moment with the following JVM flags:如果在给定的时刻,有足够多的程序在运行,以至于 1 Gb 中只有 400 Mb 是空闲的,我会在那个时刻启动一个 Java 程序,并带有以下 JVM 标志:

java -Xms256m -Xmx512m -jar myJar.jar

what happends?发生了什么事? : :

A. does the JVM fail to start right away because it will try to allocate all of the 512 Mb of memory and fail (due to the fact that there's not enough available memory at the moment)? A. JVM 是否无法立即启动,因为它会尝试分配 memory 的所有 512 Mb 并失败(因为目前没有足够的可用 memory)?

if the JVM starts:如果 JVM 启动:

if at some point the running Java process will need more than 400 Mb of memory (and there's still only 400 Mb of memory that's free other than what the current Java process has already used), what will happen:如果在某个时候运行的 Java 进程需要超过 400 Mb 的 memory(除了当前 Java 进程已经使用的空间之外,仍然只有 400 Mb 的 memory 是免费的),将会发生什么:

B. will the Java process fail with an OutOfMemroyError? B. Java 进程会因 OutOfMemroyError 而失败吗?

C. will it fail with some other (standard) error? C。它会因其他(标准)错误而失败吗?

D. is it undefined behavior? D. 是未定义的行为吗?

-Xmx just defines the maximum size of the heap. -Xmx只定义堆的最大大小。 It makes no guarantee on wether there is so much memory or not. 它不能保证有这么多的记忆。 It only ensures that the heap will never be bigger then the given value. 它只能确保堆永远不会比给定值大。 That said, Option B.) will happen, an outOfMemoryError will be thrown. 也就是说,选项B。将会发生,将抛出outOfMemoryError。

Suppose I have a Linux machine which has 1 Gb of memory which it can allocate to processes (physical and swap totals 1 Gb). 假设我有一台具有1 Gb内存的Linux机器,它可以分配给进程(物理和交换总数为1 Gb)。

My first response would be, unless you are talking about a phone, I would get more memory. 我的第一反应是,除非你在谈论手机,否则我会得到更多的记忆。 You can buy 16 GB (b = bit, B = byte) for less than $100. 您可以以低于100美元的价格购买16 GB(b =位,B =字节)。

does the JVM fail to start right away because it will try to allocate all of the 512 Mb of memory and fail (due to the fact that there's not enough available memory at the moment)? JVM是否无法立即启动,因为它将尝试分配所有512 Mb的内存并失败(由于目前没有足够的可用内存)?

This can happen if your system does not have 512 MB (plus some overhead) as it allocates the continuous virtual memory used for the heap on startup. 如果您的系统没有512 MB(加上一些开销),因为它在启动时分配用于堆的连续虚拟内存,则会发生这种情况。

Even if you have 550 MB free, the program could fail to start as it need to load more than just the heap. 即使你有550 MB空闲,程序也可能无法启动,因为它需要加载的不仅仅是堆。

will the Java process fail with an OutOfMemoryError? Java进程是否会因OutOfMemoryError而失败?

This can happen if your program uses 512 MB while running, regardless of the amount of memory your machine has. 如果您的程序在运行时使用512 MB,则无论您的计算机具有多少内存,都会发生这种情况。 This error will only occur after your JVM has started. 只有在JVM启动后才会出现此错误。 You won't get this error if it cannot start. 如果无法启动,您将不会收到此错误。

will it fail with some other (standard) error? 它会因一些其他(标准)错误而失败吗?

This is possible if you run out of swap space after the program has started. 如果在程序启动后耗尽交换空间,则可以执行此操作。 It is rare and only happens on a severely overloaded machine. 这是罕见的,只发生在严重超载的机器上。 What I have seen is the JVM crashes due to a low level OS failure to allocate memory. 我所看到的是由于低级操作系统无法分配内存而导致JVM崩溃。

Java 6 Update 25 VM crash: insufficient memory Java 6 Update 25 VM崩溃:内存不足

OutOfMemroyError will be "Thrown when the Java Virtual Machine cannot allocate an object because it is out of memory, and no more memory could be made available by the garbage collector." 当Java虚拟机无法分配对象时, OutOfMemroyError“抛出,因为内存不足,垃圾收集器无法再提供更多内存。”

So, in essence, "B. The Java process fail with an OutOfMemroyError " . 所以,实质上, “B. Java进程因OutOfMemroyError失败”

If you have so much occupied memory that the free space cannot even sustain an idle JVM, you would get either some error saying the program has not enough memory, or the JVM would crash. 如果你有太多的占用内存以至于可用空间甚至无法支持空闲JVM,那么你会得到一些错误,说程序没有足够的内存,或者JVM会崩溃。

If you can run the JVM, you can specify the limit on heap space with -Xmx. 如果可以运行JVM,则可以使用-Xmx指定堆空间限制。 That doesn't mean all the heap will be allocated by JVM on start - it is only an internal limit. 这并不意味着JVM在启动时将分配所有堆 - 它只是一个内部限制。 If the JVM will want to increase the heap space, but there is not enough memory, or you need more heap than specified by -Xmx, you will get OutOfMemoryError in currently running Java programs. 如果JVM想要增加堆空间,但没有足够的内存,或者您需要的堆比-Xmx指定的堆多,那么在当前运行的Java程序中会出现OutOfMemoryError。

In a very extreme condition, you can run out of free memory while the JVM is running, and at the same time the JVM requires more memory for its internal operation (not the heap space) - then the JVM tells you it needed more memory, but could not get any, and terminates, or it will crash outright. 在非常极端的情况下,在JVM运行时可能会耗尽可用内存,同时JVM需要更多内存用于其内部操作(而不是堆空间) - 然后JVM会告诉您它需要更多内存,但是无法得到任何东西,并且终止,否则它将彻底崩溃。

The JVM process will run in virtual memory, so the question of allocation of other processes running is relevant, but not completely determinitive. JVM进程将在虚拟内存中运行,因此运行的其他进程的分配问题是相关的,但不是完全确定的。

When the JVM cannot allocate more memory (for whatever reason), the process itself doesn't terminate, but rather starts throwing OutOfMemoryError within the JVM, but not external to the JVM. 当JVM无法分配更多内存(无论出于何种原因)时,进程本身不会终止,而是开始 JVM中抛出OutOfMemoryError ,但不在JVM外部OutOfMemoryError In other words, the JVM continues to run, but the programs running within the JVM will usually fail, because most don't handle low memory conditions adequately. 换句话说,JVM继续运行,但JVM中运行的程序通常会失败,因为大多数程序都不能充分处理低内存条件。 In this fairly common case, when the program does not do anything to handle the error, the JVM will terminate the program and exit. 在这种相当常见的情况下,当程序没有做任何事情来处理错误时,JVM将终止程序并退出。 Ultimately, this is from the memory allocation, but not directly so. 最终,这是来自内存分配,但不是直接的。 It's possible for a piece of code to scale itself back under low memory condition and continue to run. 一段代码可以在低内存条件下自行扩展并继续运行。

And others have pointed out, it happens sometimes that the JVM itself doesn't handle low memory well, but this is a pretty extreme condition. 其他人已经指出,有时JVM本身并不能很好地处理低内存,但这是一个相当极端的条件。

Despite the question being 10 years old, i was also thinking about this just today and decided to actually try this out.尽管这个问题已有 10 年历史,但我今天还在考虑这个问题,并决定实际尝试一下。 :-) :-)

  • Linux version Linux version 5.10.0-0.bpo.9-amd64 Linux 版本 Linux 版本 5.10.0-0.bpo.9-amd64
  • JVM version OpenJDK Runtime Environment (build 11.0.14+9-post-Debian-1deb10u1) JVM 版本 OpenJDK 运行环境 (build 11.0.14+9-post-Debian-1deb10u1)

Using this small test program:使用这个小测试程序:

import java.util.*;

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

on a machine having 4G of RAM and 4G swap (this is just my NAS:-) ):在具有 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
  • when running with 1G heap allowed, the process dies with an OOM:在允许 1G 堆的情况下运行时,进程会因 OOM 而终止:
tomi@unyanas:~/workspace$ java -Xmx1G OOMTest
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at OOMTest.main(OOMTest.java:9)
  • when running with 10G heap allowed, then:当允许 10G 堆运行时,则:
    • the process starts as stated above, despite not having that much RAM+swap in the machine at all该过程如上所述开始,尽管机器中根本没有那么多 RAM+swap
    • but the output is clearly not an OOM, the process is just being killed by the kernel:但是 output 显然不是 OOM,进程只是被 kernel 杀死:
tomi@unyanas:~/workspace$ java -Xmx10G OOMTest
Killed

So to summarize:所以总结一下:

  • getting an OOM when the host runs out of memoery is at least not guaranteed (i got this outcome 3 times out of 3 tries)当主机内存不足时得到 OOM 至少不能保证(我在 3 次尝试中有 3 次得到这个结果)
  • "overcommiting" the machine capacity with -Xmx is allowed允许使用 -Xmx “过度使用”机器容量
  • it really seems to be the case that getting an OOM is only guaranteed as long as the "cap" on the process is the -Xmx value (either the default or specified explicitely), but otherwise there would be more free memory (RAM+swap) left to the OS似乎只有当进程的“上限”是 -Xmx 值(默认值或明确指定)时才能保证获得 OOM,否则会有更多免费 memory(RAM + swap ) 留给操作系统

For the above one can say that this situation was created by the fact that the test code would have infinit memory footprint, so i also wanted to try if a process with high generation rate, but otherwise finit memory footprint can be made fail by setting a too high -Xmx value.对于上述情况,可以说这种情况是由于测试代码具有 infinit memory 占用空间这一事实造成的,所以我也想尝试一个具有高生成率的进程,否则 finit memory 占用空间可以通过设置-Xmx 值太高。 So if the GC can be fooled to believe that there is a lot more memory available than really is and in the end be killed, or if it will be notified by the kernel about failed OS level memory allocations and hence restrict the heap size.因此,如果 GC 可以被愚弄,相信可用的 memory 比实际多得多,并最终被杀死,或者如果 kernel 通知它失败的 OS 级别 memory 分配并因此限制堆大小。 And the answer is that it can be fooled.答案是它可以被愚弄。

i've altered the above code like this:我已经像这样更改了上面的代码:

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

When specifyint an -Xmx value that the machine can handle, the program could run any long (well i really let it run as long as i was having dinner, but you get the point:-) )当指定机器可以处理的 -Xmx 值时,程序可以运行很长时间(好吧,我真的让它运行只要我吃晚饭,但你明白了:-))

So this never exits (when enabling GC logging, once the 2G heap size is reached, a nice repeating pattern can be observed):所以这永远不会退出(当启用 GC 日志记录时,一旦达到 2G 堆大小,就可以观察到一个很好的重复模式):

java -Xmx2G OOMTest

But when running with Xmx10G, the process is killed again, wihtout an OOM:但是当使用 Xmx10G 运行时,进程再次被杀死,没有 OOM:

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

This suggests that the only "constructive feedback" the JVM gets when it attempts to allocate more memory than currently available on the host as RAM+swap is something like a kill -9.这表明,当 JVM 尝试分配比主机上当前可用的更多 memory 作为 RAM+swap 时,它获得的唯一“建设性反馈”类似于 kill -9。 And hence by using too high -Xmx values a process that would otherwise function correctly can be made fail.因此,通过使用过高的 -Xmx 值,可以使 function 正确的进程失败。 This is by no means to say that this would happen on all OS-es, JVM implementations or even just GC algorithms (i was using the default G1), but this was definitely the case with the above set up.这绝不是说这会发生在所有 OS-es、JVM 实现上,甚至只是 GC 算法(我使用的是默认 G1),但这绝对是上述设置的情况。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如果String Pool内存不足会发生什么? - What happens if String Pool runs out of memory? 如何使用JMX监视在内存不足时重启JVM? - How to restart JVM when it runs out of memory by using JMX monitoring? 异常-当JVM内存不足时,将引发哪个异常? - Exception - When the JVM runs out of memory, which exception will be thrown? OrientDB更新遇到JVM内存问题“无法分配内存” - OrientDB Update runs into JVM memory issue 'Cannot allocate memory' JVM终止后会发生什么? - What happens when the JVM is terminated? 当我们使用空花括号分配数组时,内存中究竟发生了什么? - What exactly happens in memory when we allocate an array using an empty curly braces? Java:当我的应用程序运行较长时间时出现内存不足错误 - Java : Out Of Memory Error when my application runs for longer time 当我们说垃圾收集器或GC收集对象时,JVM或内存级别会发生什么? - What happens at JVM or memory level when we say object is collected by Garbage Collector or GC? 如何配置JVM仅在确实需要时才分配内存? - How to configure JVM to allocate memory only when is really necessary? 如果我们在事务执行期间终止JVM进程会发生什么? - What happens if we kill the JVM process during transaction execution?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM