一次内存泄漏的问题记录

项目场景:

同事在开发一款人脸识别app时,在多次执行,打开--》人脸识别--》关闭--》打开循环测试过程中会耗尽内存导致被kill。


问题描述:

测试同学通过用monkey脚本测试,遇到内存泄漏的问题。

 

  • 日志片段1:可以看到系统一直在频繁gc,已经超过设定的512mb上限。

09-22 13:53:21.106  3052  3127 I zygote  : Waiting for a blocking GC Alloc
09-22 13:53:21.630  3052  5107 I zygote  : Clamp target GC heap from 535MB to 512MB
09-22 13:53:21.630  3052  5107 I zygote  : Alloc concurrent copying GC freed 38(1192B) AllocSpace objects, 0(0B) LOS objects, 0% free, 511MB/512MB, paused 167us total 1.441s
09-22 13:53:21.630  3052  3142 I zygote  : WaitForGcToComplete blocked Alloc on HeapTrim for 2.013s
09-22 13:53:21.630  3052  5107 W zygote  : Throwing OutOfMemoryError "Failed to allocate a 460812 byte allocation with 1192 free bytes and 1192B until OOM, max allowed footprint 536870912, growth limit 536870912"
09-22 13:53:21.630  3052  3142 I zygote  : Starting a blocking GC Alloc
09-22 13:53:21.630  3052  3142 I zygote  : Starting a blocking GC Alloc
09-22 13:53:21.630  3052  4168 I zygote  : Waiting for a blocking GC Alloc
09-22 13:53:21.630  3052  5107 I zygote  : Waiting for a blocking GC Alloc
09-22 13:53:21.630  3052  3806 I zygote  : Waiting for a blocking GC Alloc
09-22 13:53:21.630  3052  3127 I zygote  : Waiting for a blocking GC Alloc
09-22 13:53:21.630  3052  3061 I zygote  : Waiting for a blocking GC Alloc
09-22 13:53:22.103  3052  3142 I zygote  : Clamp target GC heap from 535MB to 512MB
09-22 13:53:22.103  3052  3142 I zygote  : Alloc concurrent copying GC freed 30(808B) AllocSpace objects, 0(0B) LOS objects, 0% free, 511MB/512MB, paused 145us total 472.588ms
09-22 13:53:22.103  3052  4168 I zygote  : WaitForGcToComplete blocked Alloc on HeapTrim for 2.484s
09-22 13:53:22.103  3052  4168 I zygote  : Starting a blocking GC Alloc
09-22 13:53:22.103  3052  4168 I zygote  : Starting a blocking GC Alloc
09-22 13:53:22.103  3052  3142 I zygote  : Waiting for a blocking GC Alloc
09-22 13:53:22.103  3052  3127 I zygote  : Waiting for a blocking GC Alloc
09-22 13:53:22.103  3052  3061 I zygote  : Waiting for a blocking GC Alloc
09-22 13:53:22.103  3052  3806 I zygote  : Waiting for a blocking GC Alloc
09-22 13:53:22.103  3052  5107 I zygote  : Waiting for a blocking GC Alloc
09-22 13:53:22.557  3052  4168 I zygote  : Clamp target GC heap from 535MB to 512MB
09-22 13:53:22.557  3052  4168 I zygote  : Alloc concurrent copying GC freed 0(0B) AllocSpace objects, 0(0B) LOS objects, 0% free, 511MB/512MB, paused 131us total 453.636ms
09-22 13:53:22.557  3052  3127 I zygote  : WaitForGcToComplete blocked Alloc on HeapTrim for 1.451s
09-22 13:53:22.557  3052  3127 I zygote  : Starting a blocking GC Alloc
09-22 13:53:22.557  3052  3142 I zygote  : WaitForGcToComplete blocked Alloc on HeapTrim for 454.347ms
09-22 13:53:22.558  3052  3142 I zygote  : Starting a blocking GC Alloc
09-22 13:53:22.558  3052  3061 I zygote  : WaitForGcToComplete blocked Alloc on HeapTrim for 2.941s
09-22 13:53:22.558  3052  3061 I zygote  : Starting a blocking GC Alloc
09-22 13:53:22.558  3052  3061 I zygote  : Starting a blocking GC Alloc
09-22 13:53:22.558  3052  3806 I zygote  : Waiting for a blocking GC Alloc
09-22 13:53:22.558  3052  5107 I zygote  : Waiting for a blocking GC Alloc
09-22 13:53:22.558  3052  4168 I zygote  : Waiting for a blocking GC Alloc
09-22 13:53:22.558  3052  3142 I zygote  : Waiting for a blocking GC Alloc
09-22 13:53:22.558  3052  3127 I zygote  : Waiting for a blocking GC Alloc
09-22 13:53:23.032  3052  3061 I zygote  : Clamp target GC heap from 535MB to 512MB
09-22 13:53:23.032  3052  3061 I zygote  : Alloc concurrent copying GC freed 23(552B) AllocSpace objects, 0(0B) LOS objects, 0% free, 511MB/512MB, paused 120us total 474.598ms
09-22 13:53:23.033  3052  3806 I zygote  : WaitForGcToComplete blocked Alloc on HeapTrim for 2.804s
09-22 13:53:23.033  3052  3806 I zygote  : Starting a blocking GC Alloc

  • 日志片段2:已经无法再分配新的内存空间

09-22 13:53:30.408  3052  3142 W System.err: java.lang.RuntimeException: Exception while computing database live data.
09-22 13:53:30.409  3052  3142 W System.err:     at androidx.room.RoomTrackingLiveData$1.run(RoomTrackingLiveData.java:92)
09-22 13:53:30.409  3052  3142 W System.err:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
09-22 13:53:30.409  3052  3142 W System.err:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
09-22 13:53:30.409  3052  3142 W System.err:     at java.lang.Thread.run(Thread.java:764)
09-22 13:53:30.409  3052  3142 W System.err: Caused by: android.database.sqlite.SQLiteException: unknown error (code 0): Native could not create new byte[]
09-22 13:53:30.409  3052  3142 W System.err:     at android.database.CursorWindow.nativeGetBlob(Native Method)
09-22 13:53:30.410  3052  3142 W System.err:     at android.database.CursorWindow.getBlob(CursorWindow.java:403)
09-22 13:53:30.410  3052  3142 W System.err:     at android.database.AbstractWindowedCursor.getBlob(AbstractWindowedCursor.java:45)
09-22 13:53:30.410  3052  3142 W System.err:     at com.decard.facediscernoffline.module_base_offline.bean.db.FaceDataDao_Impl$10.call(FaceDataDao_Impl.java:1032)
09-22 13:53:30.410  3052  3142 W System.err:     at com.decard.facediscernoffline.module_base_offline.bean.db.FaceDataDao_Impl$10.call(FaceDataDao_Impl.java:1016)
09-22 13:53:30.410  3052  3142 W System.err:     at androidx.room.RoomTrackingLiveData$1.run(RoomTrackingLiveData.java:90)
09-22 13:53:30.410  3052  3142 W System.err:     ... 3 more

原因分析:

  • 1,查询此设备的DVM分配的heap上限

adb shell getprop | grep heap  

[dalvik.vm.heapsize]: [512m]

  • 2,重复复现步骤,抓取内存申请快照hprof文件

adb shell am dumpheap com.xxx.xxx  /data/local/tmp/14_54.hprof

hprof-conv 14_54.hprof 14_54_R.hprof  

hprof-conv在sdk的platform-tools目录

 

  • 3,使用Memory Analyzer Tool进行分析

打开14_54_R.hprof 文件后,

竟然有多个activity实例,基本断定是发生了上下文的强引用导致Activity无法被回收。

 

  • 4,点击右键Paths to GC Roots-->exclude all phantom/weak/soft etc reference

发现引用的代码位置,进行排查,发现使用的都是activity的context。


解决方案:

重构代码,把需要引用上下文对象的类,都用ApplicationContext 来代替。

 

参考博客

https://blog.csdn.net/zxm317122667/article/details/52162764?utm_medium=distribute.pc_relevant_ask_down.none-task-blog-baidujs-1.nonecase&depth_1-utm_source=distribute.pc_relevant_ask_down.none-task-blog-baidujs-1.nonecase

  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在ThreadLocal中,内存泄露问题通常是由于没有正确地清理ThreadLocal对象造成的。当一个线程调用ThreadLocal的set方法设置变量时,当前线程的ThreadLocalMap里面就会存放一个Entry对象,这个记录的key为ThreadLocal的引用,value则为设置的值。如果当前线程一直存在而没有调用ThreadLocal的remove方法,并且这时候其它地方还是有对ThreadLocal的引用,则当前线程的ThreadLocalMap变量里面会存在ThreadLocal变量的引用和value对象的引用是不会被释放的,这就会造成内存泄露的。即使ThreadLocal变量没有了其他强依赖,而当前线程还存在,由于线程的ThreadLocalMap里面的key是弱依赖,那么在垃圾回收时,当前线程的ThreadLocalMap里面的ThreadLocal变量的弱引用会被回收,但是对应的value还是会造成内存泄露。因此,在使用ThreadLocal时,需要确保及时调用remove方法来清理ThreadLocal引用,以避免内存泄露的问题。另外,使用线程池的情况下,使用完ThreadLocal一定要使用remove方法即时清理,因为ThreadLocal是属于某个线程的,而在使用线程池的情况下,这些线程都是可重复利用、存活时间长的线程,如果在使用过程中不及时remove,就会造成内存泄露的问题,并且可能引发一些功能逻辑问题,比如多个请求可能获取到了线程池中同一个线程的ThreadLocal值。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [ThreadLocal的内存泄露问题](https://blog.csdn.net/sunao1106/article/details/127133911)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [记一次ThreadLocal引发的内存泄露](https://blog.csdn.net/kshzhaohui/article/details/111244981)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值