首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >试图理解内存中的Java错误并捕获可抛出的

试图理解内存中的Java错误并捕获可抛出的
EN

Stack Overflow用户
提问于 2021-06-16 09:15:44
回答 1查看 313关注 0票数 0

最近,我被要求捕捉代码中的Throwable。因此,我们遇到了一个争论,认为我们是否应该这样做,我给出了一个OutOfMemoryError的例子,在本例中,即使我们捕捉到错误,我们的代码也不会被进一步处理。

为了检验这个理论,我们为它创建了示例代码。

代码语言:javascript
复制
public class TestErrorInThread {

public static void test() {
    System.out.println("Running the test at time " + new Date());
    try {
        System.out.println("Inside try block");
        Integer[] array = new Integer[10000000 * 10000000];
    } catch (Throwable e) {
        System.out.println("Inside catch block");
        System.out.println(e);
    }
    int arr[] = new int[100];
    System.out.println("Programme is still running...");

}

public static void main(String[] args) {
    ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
    Runnable runnable = TestErrorInThread::test;
    scheduledExecutorService.scheduleAtFixedRate(runnable, 0, 5, TimeUnit.SECONDS);
}}

要运行代码,我们使用以下命令。

代码语言:javascript
复制
java -Xmx1m TestErrorInThread

我们得到了下面的输出

在时间上运行测试Wed Jun 16 14:20:31 IST 2021

内部试块

内捕块

java.lang.OutOfMemoryError: Java堆空间

节目还在运行..。

测试时间: Wed Jun 16 14:20:36 IST 2021

内部试块

内捕块

java.lang.OutOfMemoryError: Java堆空间

节目还在运行..。

在时间上运行测试Wed Jun 16 14:20:41 IST 2021

内部试块

内捕块

java.lang.OutOfMemoryError: Java堆空间

节目还在运行..。

在时间上运行测试Wed Jun 16 14:20:46 IST 2021

内部试块

内捕块

java.lang.OutOfMemoryError: Java堆空间

节目还在运行..。

在时间上运行测试Wed Jun 16 14:20:51 IST 2021

内部试块

内捕块

java.lang.OutOfMemoryError: Java堆空间

节目还在运行..。

为什么这个程序能够运行得更远,即使它摆脱了内存错误。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-06-16 14:23:39

这是代码的主要内容:

代码语言:javascript
复制
try {
    Integer[] array = new Integer[10000000 * 10000000];
} catch (Throwable e) {
    /* ... */
}
int arr[] = new int[100];

根据您的问题中的输出,这是失败的大分配,恢复和成功的小分配。

为什么这个程序能够运行得更远,甚至它摆脱了内存错误。

简短的回答:因为JVM的设计是为了在大多数情况下能够从OOME中恢复。

在您的示例中,第一个new操作符将导致对大量内存(参见下面)的内存分配请求。内存分配程序会注意到请求比可用的要大。然后(通常)会触发一个完整的垃圾收集器来释放尽可能多的内存,然后重复请求。

在本例中,仍然没有足够的内存来进行非常大的分配。然后,分配程序抛出一个OutOfMemoryError,然后像任何其他异常一样传播它。在这个时候,会有很多的自由记忆.但还不足以应付巨额拨款。

然后,代码捕获OOME,并尝试分配一个更小的数组。这是成功的,因为内存是可用的。

您的测试应用程序重复执行此序列,并且每次都执行相同的操作。

为什么这个程序能够运行得更远,甚至它摆脱了内存错误。

在您的示例中,JVM对于巨大的分配请求来说仅仅是“内存不足”。对于较小的请求,没有问题。

注意,这个巨大的new实际上并没有分配内存。它进行了测试,看看它是否能够完成分配,并决定它不能。

基本上,你的“理论”是错误的。然而,试图从海洋生态系统中捕获和恢复,通常是个坏主意。以下是一些原因:

  1. OOME很容易导致线程意外终止,使数据结构处于不一致的状态、不会发送的通知等。恢复可以是problematic.

  1. 如果恢复导致重复相同的请求,则可能会重复OOME。

  1. 如果OOME的根本原因是内存泄漏,那么从OOME恢复不太可能修复内存泄漏。因此,恢复导致OOME频率增加,直到系统停止运行。--

当然,所有这些都有例外。

还有几件事要注意。

  1. 您的分配似乎是请求一个包含10,000,000 x 10,000,000元素的数组。然而,这并不是真正发生的事情。实际上,10000000 * 10000000是一个int表达式。它溢出,结果被截断为276447232。这仍然非常大,特别是因为您需要乘以8才能得到以字节为单位的近似数组大小。

  1. ,因为您的JVM的最大堆大小只有1MB,所以很可能分配程序不会费心运行GC。这对结果没有任何影响。但是,如果GC有任何机会释放足够的内存,则可以确保它将在分配程序放弃并抛出OOME.

之前运行。

JVM的内存管理器

  1. 将堆拆分为多个空间。详细信息取决于您选择的GC。当请求一个非常大的对象时,分配程序必须找到一个适合于一个空间的连续内存区域。这不可能..。尽管总空闲空间应该足够大。
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67999751

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档