最近,我被要求捕捉代码中的Throwable。因此,我们遇到了一个争论,认为我们是否应该这样做,我给出了一个OutOfMemoryError的例子,在本例中,即使我们捕捉到错误,我们的代码也不会被进一步处理。
为了检验这个理论,我们为它创建了示例代码。
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);
}}要运行代码,我们使用以下命令。
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堆空间
节目还在运行..。
为什么这个程序能够运行得更远,即使它摆脱了内存错误。
发布于 2021-06-16 14:23:39
这是代码的主要内容:
try {
Integer[] array = new Integer[10000000 * 10000000];
} catch (Throwable e) {
/* ... */
}
int arr[] = new int[100];根据您的问题中的输出,这是失败的大分配,恢复和成功的小分配。
为什么这个程序能够运行得更远,甚至它摆脱了内存错误。
简短的回答:因为JVM的设计是为了在大多数情况下能够从OOME中恢复。
在您的示例中,第一个new操作符将导致对大量内存(参见下面)的内存分配请求。内存分配程序会注意到请求比可用的要大。然后(通常)会触发一个完整的垃圾收集器来释放尽可能多的内存,然后重复请求。
在本例中,仍然没有足够的内存来进行非常大的分配。然后,分配程序抛出一个OutOfMemoryError,然后像任何其他异常一样传播它。在这个时候,会有很多的自由记忆.但还不足以应付巨额拨款。
然后,代码捕获OOME,并尝试分配一个更小的数组。这是成功的,因为内存是可用的。
您的测试应用程序重复执行此序列,并且每次都执行相同的操作。
为什么这个程序能够运行得更远,甚至它摆脱了内存错误。
在您的示例中,JVM对于巨大的分配请求来说仅仅是“内存不足”。对于较小的请求,没有问题。
注意,这个巨大的new实际上并没有分配内存。它进行了测试,看看它是否能够完成分配,并决定它不能。
基本上,你的“理论”是错误的。然而,试图从海洋生态系统中捕获和恢复,通常是个坏主意。以下是一些原因:
当然,所有这些都有例外。
还有几件事要注意。
10000000 * 10000000是一个int表达式。它溢出,结果被截断为276447232。这仍然非常大,特别是因为您需要乘以8才能得到以字节为单位的近似数组大小。之前运行。
JVM的内存管理器
https://stackoverflow.com/questions/67999751
复制相似问题