一、Java内存分配模型
二、Java对象生命周期
1、创建:为对象分配内存,构造对象
2、应用:此时对象至少被一个强引用持有
3、不可见:程序本身不再持有这个对象,但是该对象还依然存在
4、不可达:GC对该对象进行可达性分析(判断对象是否为垃圾),发现不可达,然后就会把该对象归纳成不可达状态
三、APP内存组成
1、Java申请的内存在" vm heap " 上,所以如果申请的内存大小超过" VM "的逻辑内存限制,就会出现内存溢出。
查看APP内存限制命令:adb shell cat /system/build.prop
2、设备的物理内存 cat proc/meminfo
3、应用退到后台杀死分级
oom_adj给应用定级的一个取值,范围是 [-16 15] 数字越小,越不会容易被系统杀死
AMS 也会对应用定级,用oom_score_adj [-1000 1000],越小越不会被系统杀死
app:前台可见 0
查看OOM_ADJ 的值,cat proc/pid/oom_adj
4、内存三大问题
1、内存抖动,会导致频繁GC,然后卡顿,比如在onDraw中new Paint() 或者 new Path()
2、内存泄漏,在当前应用周期内,该对象不再使用,但是一直被GC Root持有,导致不能被回收,使实际可用内存变小。
3、内存溢出,OOM导致原因:内存不够,内存不连续,线程数量达到上限,
5、常见分析内存命令
1、dumpsys meminfo 会把当前应用进程按照内存占用情况进行排序
2、dumpsys meminfo package
如果查看到的 activities 的数量是一直增长的,那么就有可能存在内存泄漏
6、AMT工具
抓取内存快照,通过代码的方式:
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd_HH.mm.ssss");
String format = dateFormat.format(new Date(System.currentTimeMillis()));
String absolutePath = Environment.getExternalStorageDirectory().getAbsolutePath();
System.out.println("lgj : absolutePath :" + absolutePath);
File file = new File(absolutePath + "/" + format + "_lgj.hprof");
try {
android.os.Debug.dumpHprofData(file.getAbsolutePath());
System.out.println("lgj : 完成dump...");
} catch (IOException e) {
e.printStackTrace();
}
想要通过MAT工具查看,必须需要转化,转化命令如下
D:\AndroidStadio\sdk-as\platform-tools>hprof-conv.exe 2021-04-11_23.32.0016_lgj.hprof cc.hprof
public class C {
private static C myC = new C();
public static C getInstance(){
return myC;
}
private D d = new D();
private E e = new E();
public static class A{
private C c1 = C.getInstance();
}
public static class B{
private C c2 = C.getInstance();
}
public static void main(String[] args) {
A a = new A();
B b = new B();
}
}
class D{
}
class E{
}
C:incoming 该对象被谁持有,有A、B、C对象的class
outgoing 该对象持有谁,持有D、E、还有自身的C class对象
Shallow Heap:浅堆,表示自己本身占用的内存
Retained Heap:深堆,统计结果,统计自身占用的内存以及,它自己引用别的对象内存总和