android的app内存占用过大造成原因是多方面的。
activityA->activityB然后回退回activityA。重复多次。
会发现app一直内存增高,真可怕。
当然如果用demo(无隐患内存泄漏)测试则不会一直增高。最好找个复杂的项目,比如公司项目。
通过AndroidStudio Profiler进行内存分析
在主界面(activityA)进行 Profiler分析前先点击垃圾筐释放掉系统可以释放的内存,再点击旁边的 Dump java heap(在AndroidStudio3.2.1是个向下的箭头在Record旁边),然后等待系统拉去整理。然后根据Arrange by package分类,会发现activityB、activityB$1、activityB$、activityB$N等这些都是存在内存泄漏隐患的。
对于activityB$1带$符号的直接右键跳转就会找到持有者。
对于activityB不带$符的是需要具体分析的比较麻烦点,点击他,发现右边 Instance View 中会出现这个,然后再点击这个发现下边出现 References 进行系统分析哪里造成了activityB不能释放。
发现activityB$带$也会在Android的View的onClick或者onTouch(如果你写了这些监听)等系统中引用,这里其实不是系统造成的泄漏,但是为了避免影响,可以在onDestroy的时候设置setOnClick(null)或者setOnTouch(null)。
对于activityB不带$符主要分析你自定义的类到底谁没有释放,比如自定义的回调。自定义的类相互持有,只需要在需要销毁的时候释放就行了。比如onDestory中对自定义的回调release掉。比如我的myCustom在onDetroy中没有销毁,就会导致这个问题。
activity释放资源.png
当Profiler中没有ActivityB和Actiivty$N时候,把setOnClick(null)和setOnTouch(null)去掉,再次Profiler发现并没有泄漏。这只能说系统已经释放了,当我们自身有泄漏的时候,系统认为我们还需要setOnClick和setOnTouch所以既然泄漏了,系统就不释放了。因为系统不知道你是故意泄露的还是怎么着吧。
容易复现OOM 多Fragment
如果项目里在某个模块来回测试发现容易复现oom,那么就看内存增长情况。比如:我项目里发现40个Fragment(一次性初始化40个)用replace替换(其实当前值显示一个)。发现多次在当前切换oom。分析内存profiler动态图生成Dump java heap Arrange byclass过滤发现排名靠前的ArrayList点击在Instnce View中的array下有40个mMyFragments(我自己创建的方便找到第几个fragment)object(MyFragment)。果断去掉mMyFragment。采用
private ListenLookFragment getCurFragment() {
Fragment f = getSupportFragmentManager().findFragmentById(R.id.realFrameLayout);
if (f instanceof MyFragment) {
return (ListenLookFragment) f;
}
return null;
}
来获取当前Fragment。通过测试就算40个fragment来回repleace内存很稳定不会一直增加。
网友评论