Android应用程序中的内存分配问题

27

我有一个Android应用程序,执行图像分析,使用IntentService进行管理 - 每次处理需要几秒钟时间,工作精确且快速。

但是,当在应用程序中重复该过程约50次(如所示),它开始变得非常缓慢,直到应用程序和设备变得无法使用。当重新启动设备并再次打开应用程序时,它会像往常一样运行。

使用Android Studio检查,每次运行分析时,我可以看到应用程序的内存分配每次都会增加约1MB。因此,当它崩溃时,显然已经耗尽了内存。

我已经在完成分析并进入结果时使用了此标志,以尝试修复后台活动;

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

虽然我知道IntentService会自行关闭管理,但它的影响很小。所以我不确定还能做什么来尝试减少内存分配,或者至少清理分配并停止添加到其中的内容?

图像分析工作流程

更多细节:

  • 应用程序正在使用基于Google Camera2的相机实现
  • 通过IntentService使用C++库进行分析。

4
如果你比较两次运行的堆转储,你应该能够看到某个类的实例数量增加了。这是找出泄漏原因的起点和线索。(除非问题在于C++库或其使用方式,否则我不确定要寻找什么。) - Kevin Krumwiede
你有没有尝试在两次运行之间强制进行垃圾回收?Runtime.getRuntime().gc(); - Grisgram
2
你是如何保存图片以便进行分析的?我之前遇到了类似的问题,但通过使用弱引用得以解决。 - Josef Korbel
考虑使用以下两个语句,我曾遇到类似的问题,它们可以释放未使用的资源: System.runFinalization(); System.gc(); - Apar Amin
2
问题中没有足够的信息给出任何有意义的指导除了分析内存使用情况和堆转储。展示一些代码,特别是内存分配部分。如果没有要收集的对象,那么调整GC是毫无意义的。 - aha
显示剩余2条评论
4个回答

10
似乎你没有正确地处理资源(变量、图像文件等),这导致了应用程序中的内存泄漏。
在这篇博客Johan撰写的中,你可以找到如何处理应用程序中的内存泄漏。或者查看这个SO问题。 避免Android上的内存泄漏 如果内存泄漏是在C++库中生成的,则可以在调试模式下轻松查找泄漏内存的资源。
在结果活动之后,建议执行垃圾回收器并关闭任何未使用的资源。
如果你能在问题中提供堆栈跟踪,那就更好了。

在阅读了手动调用垃圾回收器会是徒劳无功并且比本地垃圾逻辑效率低得多的内容后,我避免了自己手动调用垃圾回收器,但我会尝试一下。还有你关于文件管理的其他建议。 - Stacker-flow
调用垃圾回收器几乎不可能产生任何影响,系统会在适当的时候调用它,更有可能的是你正在做@S所说的事情。 - SBC
调用垃圾回收器几乎不可能产生任何影响,系统会在适当的时候调用它,更有可能的是你正在做@Stacker-flow建议的事情,可以尝试使用ddms内存管理工具,在你认为应该被收集的时候进行强制垃圾回收并生成堆转储以帮助查找泄漏和占用最多内存的内容。该过程在https://developer.android.com/topic/performance/memory.html中有描述,并提供了链接的页面。 - SBC

2
尝试使用LeakCanary https://github.com/square/leakcanary 查找导致内存泄漏的原因,并使用弱引用 https://developer.android.com/reference/java/lang/ref/WeakReference.html 允许在必要时进行垃圾回收。还有可能是您正在使用的设备没有足够的内存来同时保存50个高分辨率图像。如果您将它们保留在内存中,可以尝试降低图像的分辨率,并确保回收位图 https://developer.android.com/topic/performance/graphics/manage-memory.html
另外,我建议考虑使用ThreadPoolExecutor而不是IntentService,它们的可配置性更强 https://developer.android.com/reference/java/util/concurrent/ThreadPoolExecutor.html

1

我想在Ali786的回答中补充一些内容。

如果要重复调用服务,Intent Services并不是最好的选择。下一次调用服务时,它会进入队列。 Intent Services的工作方式类似于HandlerThreads。它们有自己的消息队列,当你使用Intent启动服务后,它将等待上一个服务完成。

在UI线程上运行的普通服务是并行运行的。

我不确定在您将分析信息发送到活动后是否还要执行其他操作,但如果是这样,意图服务将不会停止,下一个服务将不得不等待。 Intent服务不是与UI线程通信的最佳选择,在您的情况下,Asynctask可能更好。如果您提供更多信息(代码),也许我们可以给您一个更准确的答案。 希望这可以帮助您!


1
谢谢您的建议,但我之前已经重构了应用程序并改用了IntentServices。这是因为在使用AsyncTasks时,分析需要大约10秒钟。现在,使用IntentServices平均只需0-2秒钟。 - Stacker-flow
你尝试过使用Service吗?不是IntentService,你可以在其中放置一个线程并执行任何你想做的操作。你是如何与UI线程通信的呢? - T.Dimitrov
IntentService被启动后,当分析完成时,它通过公共方法将结果对象传回Activity,该方法存储结果,然后转到结果页面。我没有涉及任何直接的线程管理。 - Stacker-flow

0

有一件事可能会发生这样的情况,如果您的工作意图服务在工作完成后可能没有销毁该服务

在设置中检查正在运行的服务列表,查看您的应用程序的运行服务


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接