如何查看内存泄露https://blog.csdn.net/xyq046463/article/details/51769728
https://www.jianshu.com/p/48475df838d9
https://www.jianshu.com/p/cbe2ee08ca02
adb shell dumpsys activity | grep mFocusedActivity
可以查看当前正在展示的activity的信息,后边那个grep好像是linux的,我就用了前半部分,展示了好多信息,不过稍微往上滑一点就能看到
ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
Display #0 (activities from top to bottom):
Stack #1:
Task id #1504
TaskRecord{58cb3ac #1504 A=com.magellangps.SmartGPS U=0 sz=2}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.xxx.SmartGPS/.StartupActivity }
Hist #1: ActivityRecord{b5bc1bd u0 com.xxx.SmartGPS/.NavigationActivity t1504}
Intent { flg=0x14000000 cmp=com.xxx.SmartGPS/.NavigationActivity }
ProcessRecord{b8d5b25 18169:com.xxx.SmartGPS/u0a346}
Hist #0: ActivityRecord{1039b10 u0 com.xxx.SmartGPS/.MainActivity t1504}
Intent { flg=0x10000000 cmp=com.xxx.SmartGPS/.MainActivity (has extras) }
ProcessRecord{b8d5b25 18169:com.xxx.SmartGPS/u0a346}
Running activities (most recent first):
TaskRecord{58cb3ac #1504 A=com.xxx.SmartGPS U=0 sz=2}
Run #1: ActivityRecord{b5bc1bd u0 com.xxx.SmartGPS/.NavigationActivity t1504}
Run #0: ActivityRecord{1039b10 u0 com.xxx.SmartGPS/.MainActivity t1504}
mResumedActivity: ActivityRecord{b5bc1bd u0 com.xxx.SmartGPS/.NavigationActivity t1504}
adb在sdk的platform-tools目录下
adb如果没有配置环境变量的话,自己切换cmd下的目录到对应的目录即可
adb shell dumpsys meminfo com.xx.xxx
adb shell dumpsys meminfo com.xxx.demo0108
通过adb shell dumpsys meminfo
来查看内存使用状况
在没有打开应用的情况下,该命令返回的数据是这样的:
打开这个应用的MainActivity,再通过命令查看:
Android adb命令打印activity堆栈
adb shell dumpsys activity | findstr Run
内存泄露的一个例子
如下代码:
import java.util.ArrayList;
public class ManagerTest {
public static ManagerTest managerTest;
public static ManagerTest getInstance() {
if(managerTest==null) {
managerTest=new ManagerTest();
}
return managerTest;
}
ArrayList listeners=new ArrayList();
public void registerListener(TestListener listener) {
listeners.add(listener);
}
public interface TestListener{
abstract void nothing();
}
}
然后在activity使用了如下的代码,就内存泄露了,这个activity就一直存在了。
//内存泄露测试
ManagerTest.getInstance().registerListener(new TestListener() {
@Override
public void nothing() {
}
});
解决办法就是在页面销毁的时候取消注册这个listener。所以这个listener得写到外边弄个变量保存。
另外一种如果不好取消注册的,可以如下图,把这个注册的listener置为空也可以好像不行
TestListener listener=new TestListener() {
@Override
public void nothing() {
}
};
@Override
protected void onDestroy() {
listener=null;
super.onDestroy();
}
总结一下,上边的也就是匿名内部类了吧,那个TestListener()接口,这玩意基本都会引起内存泄露的
获取连接到的设备信息
adb devices
C:\Users\xxx>adb shell "pm list packages" find samsung
package:com.samsung.android.app.galaxyfinder
打印设备/模拟器上的所有软件包
adb shell "pm list packages"
过滤名字
C:\Users\charlie.song>adb shell "pm list packages" -e samsung
package:com.sec.android.widgetapp.samsungapps
package:com.samsung.android.app.galaxyfinder
package:com.samsung.clipboardsaveservice
package:com.samsung.android.provider.shootingmodeprovider
其他的一些option看这里
https://blog.csdn.net/henni_719/article/details/62222439
eclipse 内存分析工具
http://www.eclipse.org/mat/ 下边有下载地址
或 在 eclipse ->install new software -> http://download.eclipse.org/mat/1.6/update-site/ 进行安装
然后找篇介绍咋用 的
https://www.cnblogs.com/yxysuanfa/p/6811140.html
切换到DDMS页面,左上角如图,点击按钮,会提示保存,当前的内存信息到一个文件[没有插件是这样的]
你得从设备下边点击一下你要分析的app的包名,然后上边按钮才是可用状态
我是弄的插件,点击完按钮会直接弹出下边的框框,finish即可
完事就会弹出一个下边的页面,选择histogram,顶部的菜单或者下边那个都行
然后你会看到几十条,最后一行会告诉你有比如4000条这里就显示了30条。所以过滤条件就很有必要了。
输入你怀疑内存泄露的类的名字,回车过滤,下图为过滤的结果
然后如下图,找到关联的
然后发现太多了,继续过滤掉,选最后一个,
然后就会少很多,我这里过滤完就剩下一个context被引用了,会提示你哪个类的
然后找到这个类里的context,看是哪里传进来的,自然就知道是哪里的问题,然后就想办法是放掉。
context被一个静态变量给持有了
有个wifi的页面,最后查出来是这样的,刚开始完全不知道哪里有问题
搜了下wifimanager的类
private static AsyncChannel sAsyncChannel;
//init方法里初始化的,可以看到
sAsyncChannel = new AsyncChannel();
sConnected = new CountDownLatch(1);
sHandlerThread.start();
Handler handler = new ServiceHandler(sHandlerThread.getLooper());
sAsyncChannel.connect(mContext, handler, messenger);
//进入到connect方法,其实可以猜到context被保存在了AsyncChannel类里了
/** Context for source */
private Context mSrcContext;
//一个静态变量持有了这个context,所以这个context的页面也就内存泄露了
所以最后修改的地方就是获取wifimanager的时候,用application的上下文
protected WifiManager getWifiManager()
{
return (WifiManager) MainApplication.getAppContext().getSystemService(Context.WIFI_SERVICE);
}
kotlin的写法
https://proandroiddev.com/how-kotlin-helps-you-avoid-memory-leaks-e2680cf6e71e
最近看了个帖子,kotlin的写法
在一个activity里调用下边的方法,然后关闭页面,然后发现没有内存泄露一说
private fun testR(){
thread {
Thread.sleep(15000)
}
}
另一种,引用了activity里的一个变量,结果就不一样,会内存泄露的。
var aa=1
private fun testR(){
thread {
aa=2
Thread.sleep(15000)
}
}