【问题标题】:How do I catch an OutOfMemoryError before it crashes my application?如何在 OutOfMemoryError 使我的应用程序崩溃之前捕获它?
【发布时间】:2015-06-25 12:22:09
【问题描述】:

我编写了一个 Android 应用程序,并在其中实现了求解器。求解器分配了大量内存。对于简单的问题,它可以毫无问题地工作。但是当问题变得更加复杂时,我会收到错误消息“2164 字节分配内存不足”并且应用程序崩溃。

我尝试使用

try {
        solver();
}
catch (Exception e) {
}

但这并不能防止应用崩溃。

我还在 AndroidManifest.xml 中尝试了"android:largeHeap="true"

有没有办法获得更多内存或在内存满之前停止求解器?

04-18 11:39:10.953: D/dalvikvm(979): GC_FOR_ALLOC freed 25K, 5% free 31446K/32768K, paused 363ms, total 363ms
04-18 11:39:10.953: I/dalvikvm-heap(979): Forcing collection of SoftReferences for 93404-byte allocation
04-18 11:39:11.283: I/dalvikvm-heap(979): Clamp target GC heap from 32.832MB to 32.000MB
04-18 11:39:11.293: D/dalvikvm(979): GC_BEFORE_OOM freed <1K, 5% free 31445K/32768K, paused 331ms, total 332ms
04-18 11:39:11.293: E/dalvikvm-heap(979): Out of memory on a 93404-byte allocation.
04-18 11:39:11.293: I/dalvikvm(979): "AdWorker #1" prio=5 tid=11 RUNNABLE
04-18 11:39:11.293: I/dalvikvm(979):   | group="main" sCount=0 dsCount=0 obj=0xb48db908 self=0xb7ecf560
04-18 11:39:11.293: I/dalvikvm(979):   | sysTid=1015 nice=10 sched=0/0 cgrp=apps/bg_non_interactive handle=-1209206344
04-18 11:39:11.303: I/dalvikvm(979):   | state=R schedstat=( 2590000000 85040000000 791 ) utm=236 stm=23 core=0
04-18 11:39:11.303: I/dalvikvm(979):   at java.lang.AbstractStringBuilder.enlargeBuffer(AbstractStringBuilder.java:~94)
04-18 11:39:11.303: I/dalvikvm(979):   at java.lang.AbstractStringBuilder.append0(AbstractStringBuilder.java:162)
04-18 11:39:11.303: I/dalvikvm(979):   at java.lang.StringBuilder.append(StringBuilder.java:311)
04-18 11:39:11.313: I/dalvikvm(979):   at com.google.android.gms.internal.eo.a((null):-1)
04-18 11:39:11.313: I/dalvikvm(979):   at com.google.android.gms.internal.dx.a((null):-1)
04-18 11:39:11.313: I/dalvikvm(979):   at com.google.android.gms.internal.dx.a((null):-1)
04-18 11:39:11.313: I/dalvikvm(979):   at com.google.android.gms.internal.dx.b((null):-1)
04-18 11:39:11.313: I/dalvikvm(979):   at com.google.android.gms.internal.dq.a((null):-1)
04-18 11:39:11.313: I/dalvikvm(979):   at com.google.android.gms.internal.dq.bh((null):-1)
04-18 11:39:11.313: I/dalvikvm(979):   at com.google.android.gms.internal.em$1.run((null):-1)
04-18 11:39:11.313: I/dalvikvm(979):   at com.google.android.gms.internal.en$1.run((null):-1)
04-18 11:39:11.313: I/dalvikvm(979):   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
04-18 11:39:11.313: I/dalvikvm(979):   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
04-18 11:39:11.313: I/dalvikvm(979):   at java.lang.Thread.run(Thread.java:841)
04-18 11:39:11.333: I/Choreographer(979): Skipped 83 frames!  The application may be doing too much work on its main thread.
04-18 11:39:11.393: W/dalvikvm(979): threadid=11: thread exiting with uncaught exception (group=0xb3a7eba8)
04-18 11:39:11.873: I/dalvikvm-heap(979): Clamp target GC heap from 32.746MB to 32.000MB
04-18 11:39:11.883: D/dalvikvm(979): GC_FOR_ALLOC freed 132K, 5% free 31357K/32768K, paused 426ms, total 426ms
04-18 11:39:11.903: I/Choreographer(979): Skipped 44 frames!  The application may be doing too much work on its main thread.
04-18 11:39:12.613: I/dalvikvm-heap(979): Clamp target GC heap from 32.793MB to 32.000MB
04-18 11:39:12.633: D/dalvikvm(979): GC_FOR_ALLOC freed 163K, 5% free 31405K/32768K, paused 488ms, total 489ms
04-18 11:39:13.013: I/dalvikvm-heap(979): Clamp target GC heap from 32.796MB to 32.000MB
04-18 11:39:13.013: D/dalvikvm(979): GC_FOR_ALLOC freed 12K, 5% free 31409K/32768K, paused 374ms, total 374ms
04-18 11:39:13.013: I/dalvikvm-heap(979): Forcing collection of SoftReferences for 2162-byte allocation
04-18 11:39:13.373: I/dalvikvm-heap(979): Clamp target GC heap from 32.796MB to 32.000MB
04-18 11:39:13.373: D/dalvikvm(979): GC_BEFORE_OOM freed <1K, 5% free 31409K/32768K, paused 354ms, total 355ms
04-18 11:39:13.373: E/dalvikvm-heap(979): Out of memory on a 2162-byte allocation.
04-18 11:39:13.373: I/dalvikvm(979): "AdWorker #1" prio=5 tid=11 RUNNABLE
04-18 11:39:13.373: I/dalvikvm(979):   | group="main" sCount=0 dsCount=0 obj=0xb48db908 self=0xb7ecf560
04-18 11:39:13.373: I/dalvikvm(979):   | sysTid=1015 nice=10 sched=0/0 cgrp=apps/bg_non_interactive handle=-1209206344
04-18 11:39:13.383: I/dalvikvm(979):   | state=R schedstat=( 3560000000 85730000000 847 ) utm=331 stm=25 core=0
04-18 11:39:13.383: I/dalvikvm(979):   at java.lang.AbstractStringBuilder.enlargeBuffer(AbstractStringBuilder.java:~94)
04-18 11:39:13.383: I/dalvikvm(979):   at java.lang.AbstractStringBuilder.append0(AbstractStringBuilder.java:124)
04-18 11:39:13.383: I/dalvikvm(979):   at java.lang.StringBuffer.append(StringBuffer.java:278)
04-18 11:39:13.383: I/dalvikvm(979):   at java.io.StringWriter.write(StringWriter.java:123)
04-18 11:39:13.383: I/dalvikvm(979):   at com.android.internal.util.FastPrintWriter.flushLocked(FastPrintWriter.java:358)
04-18 11:39:13.383: I/dalvikvm(979):   at com.android.internal.util.FastPrintWriter.flush(FastPrintWriter.java:387)
04-18 11:39:13.383: I/dalvikvm(979):   at android.util.Log.getStackTraceString(Log.java:335)
04-18 11:39:13.383: I/dalvikvm(979):   at android.util.Slog.e(Slog.java:77)
04-18 11:39:13.383: I/dalvikvm(979):   at com.android.internal.os.RuntimeInit$UncaughtHandler.uncaughtException(RuntimeInit.java:80)
04-18 11:39:13.383: I/dalvikvm(979):   at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:693)
04-18 11:39:13.393: I/dalvikvm(979):   at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:690)
04-18 11:39:13.713: I/dalvikvm-heap(979): Clamp target GC heap from 32.799MB to 32.000MB
04-18 11:39:13.723: D/dalvikvm(979): GC_FOR_ALLOC freed 7K, 5% free 31412K/32768K, paused 327ms, total 327ms
04-18 11:39:13.723: I/dalvikvm-heap(979): Forcing collection of SoftReferences for 2164-byte allocation
04-18 11:39:14.063: I/dalvikvm-heap(979): Clamp target GC heap from 32.799MB to 32.000MB
04-18 11:39:14.063: D/dalvikvm(979): GC_BEFORE_OOM freed 0K, 5% free 31412K/32768K, paused 344ms, total 345ms
04-18 11:39:14.073: E/dalvikvm-heap(979): Out of memory on a 2164-byte allocation.
04-18 11:39:14.073: I/dalvikvm(979): "AdWorker #1" prio=5 tid=11 RUNNABLE
04-18 11:39:14.073: I/dalvikvm(979):   | group="main" sCount=0 dsCount=0 obj=0xb48db908 self=0xb7ecf560
04-18 11:39:14.073: I/dalvikvm(979):   | sysTid=1015 nice=10 sched=0/0 cgrp=apps/bg_non_interactive handle=-1209206344
04-18 11:39:14.073: I/dalvikvm(979):   | state=R schedstat=( 4210000000 85770000000 885 ) utm=395 stm=26 core=0
04-18 11:39:14.073: I/dalvikvm(979):   at java.lang.AbstractStringBuilder.enlargeBuffer(AbstractStringBuilder.java:~94)
04-18 11:39:14.073: I/dalvikvm(979):   at java.lang.AbstractStringBuilder.append0(AbstractStringBuilder.java:124)
04-18 11:39:14.073: I/dalvikvm(979):   at java.lang.StringBuffer.append(StringBuffer.java:278)
04-18 11:39:14.073: I/dalvikvm(979):   at java.io.StringWriter.write(StringWriter.java:123)
04-18 11:39:14.073: I/dalvikvm(979):   at com.android.internal.util.FastPrintWriter.flushLocked(FastPrintWriter.java:358)
04-18 11:39:14.073: I/dalvikvm(979):   at com.android.internal.util.FastPrintWriter.flush(FastPrintWriter.java:387)
04-18 11:39:14.073: I/dalvikvm(979):   at android.util.Log.getStackTraceString(Log.java:335)
04-18 11:39:14.073: I/dalvikvm(979):   at android.util.Slog.e(Slog.java:77)
04-18 11:39:14.073: I/dalvikvm(979):   at com.android.internal.os.RuntimeInit$UncaughtHandler.uncaughtException(RuntimeInit.java:88)
04-18 11:39:14.073: I/dalvikvm(979):   at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:693)
04-18 11:39:14.083: I/dalvikvm(979):   at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:690)
04-18 11:39:14.083: I/Process(979): Sending signal. PID: 979 SIG: 9

【问题讨论】:

  • “但是当问题变得更加复杂时,我会收到错误消息“2164 字节分配内存不足”并且应用程序崩溃“-您的堆碎片足够多,没有更多的 2164-字节或更大的可用内存块。 “但这并不能防止应用程序崩溃”——OutOfMemoryError 不是ExceptionIt is an Error。 “有没有办法获得更多内存”——不是来自 Android SDK。 “或者在内存满之前停止求解器?” -- 不具体。
  • 一般来说,您可以在ActivityManager 上使用getMemoryClass()getLargeMemoryClass() 来确定您的堆可以有多大。然后,将其用作在您可能获得OutOfMemoryError 之前可以分配多少的指南。但是,您可能应该考虑尝试确定您的求解器为何占用如此多的 RAM。
  • “但是,您可能应该考虑尝试确定您的求解器为何占用如此多的 RAM” 您是对的。这是唯一真正的解决方案。我发现了我以前记忆力很大的问题。谢谢。

标签: java android memory crash heap-memory


【解决方案1】:

内存不足不是一个例外,它是一个错误——您的程序不太可能从中恢复的状态。错误不是异常,所以捕获异常是行不通的。

如果你真的想抓住它,请使用OutOfMemoryError

try {
  expensiveMethod();
} catch (OutOfMemoryError e) {
  // ...
}

请注意,如果您发现此问题,您的意思是“我知道如何处理内存不足的情况”。这不太可能是真的;您的程序已经处于不稳定状态,任何进一步的分配都可能会触发另一个 OOME。

有没有办法获得更多内存 [...]?

正确的解决方案是让您的程序一次使用更少的资源。例如,您可以将求解器的工作分块为离散块,并在工作变得太大时增量存储(例如,通过将其写入磁盘)。稍后,当您需要最终解决方案时,将已解析的块加载回内存并组装它们。

有没有办法 [...] 在内存已满之前停止求解器?

您可以监控应用的当前内存使用情况:

MemoryInfo mi = new MemoryInfo();
ActivityManager a = (ActivityManager)getSystemService(ACTIVITY_SERVICE);
a.getMemoryInfo(mi);

并据此采取一些行动。但是一旦你真的内存不足,再做任何有用的事情可能已经太晚了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-18
    • 2014-03-02
    • 1970-01-01
    • 2016-01-27
    • 2011-02-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多