繁体   English   中英

修复 OutOfMemoryErrors

[英]Fixing OutOfMemoryErrors

大家好,我发现在我们最近的 Android 版本中,有关 memory 泄漏的崩溃大幅增加。 我们已经做了一些事情来尝试缓解这些问题,但在最新版本中仍然看到同样的崩溃。

 Fatal Exception: java.lang.OutOfMemoryError
 Failed to allocate a 16 byte allocation with 1890136 free bytes and 1845KB until OOM, target footprint 201326592, growth limit 201326592; failed due to fragmentation (largest possible contiguous allocation 54788096 bytes)
 java.lang.Long.valueOf (Long.java:845)
 io.reactivex.internal.operators.observable.ObservableInterval$IntervalObserver.run (ObservableInterval.java:82)
 io.reactivex.Scheduler$PeriodicDirectTask.run (Scheduler.java:562)
 io.reactivex.Scheduler$Worker$PeriodicTask.run (Scheduler.java:509)
 io.reactivex.internal.schedulers.ExecutorScheduler$ExecutorWorker$BooleanRunnable.run (ExecutorScheduler.java:288)
 io.reactivex.internal.schedulers.ExecutorScheduler$ExecutorWorker.run (ExecutorScheduler.java:253)
 java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1167)
 java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:641)
 java.lang.Thread.run (Thread.java:923)
 Fatal Exception: java.lang.OutOfMemoryError
 Failed to allocate a 16 byte allocation with 1590248 free bytes and 1552KB until OOM, target footprint 201326592, growth limit 201326592; failed due to fragmentation (largest possible contiguous allocation 39845888 bytes)
 io.reactivex.internal.schedulers.ExecutorScheduler$ExecutorWorker.schedule (ExecutorScheduler.java:161)
 io.reactivex.internal.schedulers.ExecutorScheduler$ExecutorWorker.schedule (ExecutorScheduler.java:187)
 io.reactivex.Scheduler$Worker$PeriodicTask.run (Scheduler.java:531)
 io.reactivex.internal.schedulers.ExecutorScheduler$ExecutorWorker$BooleanRunnable.run (ExecutorScheduler.java:288)
 io.reactivex.internal.schedulers.ExecutorScheduler$ExecutorWorker.run (ExecutorScheduler.java:253)
 java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1167)
 java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:641)
 java.lang.Thread.run (Thread.java:923)
 Fatal Exception: java.lang.OutOfMemoryError
 Failed to allocate a 16 byte allocation with 1215008 free bytes and 1186KB until OOM, target footprint 201326592, growth limit 201326592; failed due to fragmentation (largest possible contiguous allocation 49020928 bytes)
 io.reactivex.internal.queue.MpscLinkedQueue.offer (MpscLinkedQueue.java:62)
 io.reactivex.internal.schedulers.ExecutorScheduler$ExecutorWorker.schedule (ExecutorScheduler.java:167)
 io.reactivex.internal.schedulers.ExecutorScheduler$ExecutorWorker.schedule (ExecutorScheduler.java:187)
 io.reactivex.Scheduler$Worker$PeriodicTask.run (Scheduler.java:531)
 io.reactivex.internal.schedulers.ExecutorScheduler$ExecutorWorker$BooleanRunnable.run (ExecutorScheduler.java:288)
 io.reactivex.internal.schedulers.ExecutorScheduler$ExecutorWorker.run (ExecutorScheduler.java:253)
 java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1167)
 java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:641)
 java.lang.Thread.run (Thread.java:923)

是否存在触发这些问题的某些框架更改,是否是导致此问题的应用程序代码? 尝试解决上述崩溃的一些策略是什么?

除了现有评论之外,还需要考虑其他一些技术:

现场仪表:

活动模式:如果您有记录用户活动的内容,请查找 go 长时间没有崩溃的应用程序和较早崩溃的应用程序,看看用户是否执行了不同的操作

直接 Memory 用法:由于您还无法在调试版本中重现此问题,您可以记录在特定活动之前和之后可用的 memory,以帮助您缩小在应用程序中发生这种情况的位置。 您可以访问可用的应用程序 memory ,然后记录它(如果您可以获得日志)或通过某些分析系统将其报告回来。

本地测试:

(使用 Leak Canary 或分析器)

通常有一些时间点应该回到与分配的 memory 相同的水平:例如,如果您 go 进入屏幕并返回,您可能会分配一些 static 项目,但是从第二次使用屏幕开始,您将需要 memory回到正常(静止)点。 所以停止执行,强制 GC,重新启动执行并完成工作流,然后返回主屏幕。 (再次跳过第一次)可以是缩小哪个工作流留下大量额外 memory 的好方法。

调试版本没有产生这种效果是不寻常的,如果你有一个“友好的”最终用户报告这个问题,也许给他们一个调试版本并请求他们通过使用它来支持你。

在调试环境中,您还可以尝试“让它变得更糟”,例如,go 进出屏幕或工作流 10 次或 100 次(针对 100 次示例编写脚本)。

您不能动态增加堆大小,但可以通过使用请求使用更多。

android:largeHeap="true"

manifest.xml中,您可以在清单中添加这些行,它适用于某些情况。

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:largeHeap="true"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">

您的应用程序进程是否应使用大型 Dalvik 堆创建。 这适用于为应用程序创建的所有进程。 它仅适用于加载到进程中的第一个应用程序; 如果您使用共享用户 ID 来允许多个应用程序使用一个进程,则它们都必须一致地使用此选项,否则它们将产生不可预知的结果。 大多数应用不需要这个,而是应该专注于减少整体 memory 使用以提高性能。 启用此功能也不能保证可用 memory 的固定增加,因为某些设备受其总可用 memory 的限制。

要在运行时查询可用的 memory 大小,请使用方法 getMemoryClass() 或 getLargeMemoryClass()。

使用Coroutines进行长时间或繁重的操作。 这些崩溃来自Rxjava 也许您在这方面没有准确地执行工作。

我只是想看看您可以查看的位置,从堆栈跟踪来看,您似乎正在使用计划执行任务。 我怀疑您正在运行多个线程,并且由于每个线程都需要自己分配 memory ,因此需要考虑的一些事情是:通过线程池控制线程数,这将限制可用线程数并回收线程而不是分配新线程并可能同时运行大量线程。

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM