一、内存&空间信息
- 系统内存情况: 当系统可用内存很小(低于 MemTotal 的 10%)时,OOM、大量 GC、系统频繁自杀拉起等问题都非常容易出现
ActivityManager activityManager = (ActivityManager) ctx.getSystemService(Context.ACTIVITY_SERVICE);
ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
activityManager.getMemoryInfo(memoryInfo);
return "当前系统处于低内存状态:" + memoryInfo.lowMemory + " avail Mem:" + getMb(memoryInfo.availMem)
+ " 如果availMem>=" + memoryInfo.threshold + "时触发Low Memory Killer机制";
- 应用使用内存:
Runtime runtime = Runtime.getRuntime();
String usedMemorySize = Formatter.formatFileSize(ctx, runtime.totalMemory() - runtime.freeMemory());
String theoryAvailHeapSize = Formatter.formatFileSize(ctx, runtime.maxMemory());
return "当前进程Java虚拟机已用堆内存:" + usedMemorySize + " 理论最大可用内存:" + theoryAvailHeapSize;
-
OOM时内存快照:dump文件Size依然是主要问题,不能线上使用,没有好的解决办法。
微信解决方案:github.com/Tencent/mat…
-
存储空间信息
/**
* @return 系统内部存储可用空间
*/
public static String getAvailableInternalMemorySize(Context ctx) {
File path = Environment.getDataDirectory();
StatFs stat = new StatFs(path.getPath());
long blockSize = stat.getBlockSizeLong();
long availableBlocks = stat.getAvailableBlocksLong();
return Formatter.formatFileSize(ctx, availableBlocks * blockSize);
}
/**
* @return 系统外部存储可用空间
*/
public static String getAvailableExternalMemorySize(Context ctx) {
if (externalMemoryAvailable()) {
File path = Environment.getExternalStorageDirectory();
StatFs stat = new StatFs(path.getPath());
long blockSize = stat.getBlockSizeLong();
long availableBlocks = stat.getAvailableBlocksLong();
return Formatter.formatFileSize(ctx, availableBlocks * blockSize);
} else {
return "ERROR";
}
}
- 进程整体概况 /proc/pid/status
Name: com.xmamiga.name // 进程名
State: R (running)
FDSize: 256 //该字段是表示当前进程分配过的文件描述符的近似的最高值。如果刚开始打开了18个文件,则这里的FDSize等于32,若大于32,则以32为单位递增,例如33则是64;这个32的单位是依赖于系统位数的,如果是32位则是32,若是64位系统则是以64倍增。
VmPeak: 2070428 kB //虚拟内存峰值
VmSize: 2056588 kB //已经使用的虚拟内存大小
VmLck: 0 kB //已经锁住的物理内存的大小(锁住的物理内存不能交换到硬盘)
VmPin: 0 kB
VmHWM: 205460 kB //进程所使用的物理内存的峰值
VmRSS: 194716 kB //进程当前使用的物理内存的大小
VmData: 314280 kB //进程占用的数据段大小
VmStk: 8196 kB //进程占用的栈大小
VmExe: 20 kB //进程占用的代码段大小(不包括库)
VmLib: 188660 kB //进程所加载的动态库所占用的内存大小(可能与其它进程共享)
VmPTE: 1364 kB //进程占用的页表大小(交换表项数量)
VmPMD: 16 kB V
mSwap: 5312 kB //进程所使用的交换区的大小
Threads: 98
二、资源信息
-
线程数 Thread.activeCount()
一个线程可能就占 2MB 的虚拟内存,过多的线程会对虚拟内存和文件句柄带来压力。一般如果线程数超过 400 个就比较危险。
ThreadGroup threadGroup = Thread.currentThread().getThreadGroup(); int count = threadGroup.activeCount(); Thread[] threads = new Thread[count]; int enumerateCount = threadGroup.enumerate(threads); for (int i = 0; i < enumerateCount; i++) { Thread thread = threads[i]; QLog.d("ThreadInfo: ",thread.getName() + " Priority:" + thread.getPriority() + " State:" +thread.getState()); } 列举线程所有信息(举例) queued-work-looper Priority:5 State:RUNNABLE queued-work-looper Priority:5 State:RUNNABLE CrAsyncTask #1 Priority:5 State:TIMED_WAITING QAV Priority:5 State:RUNNABLE QAVStorage Priority:5 State:RUNNABLE HomeTask #1 Priority:5 State:WAITING -
系统最大线程数
如果超过系统最大线程数,在创建时也会抛出oom cat /proc/sys/kernel/threads-max 权限问题,暂没有获取到 参考资料:mccxj.github.io/blog/201712…
-
文件句柄 fd
最大文件句柄数: /proc/pid/limits (内容见下表)
一般单个进程允许打开的最大文件句柄个数为 1024。但是如果文件句柄超过 800 个就比较危险,需要将所有的 fd 以及对应的文件名输出到日志中,进一步排查是否出现了有文件或者线程的泄露
Limit Soft Limit Hard Limit Units Max stack size 8388608 unlimited bytes Max core file size 0 unlimited bytes Max processes 22028 22028 processes Max open files 2048 4096 files // 最大打开文件句柄数 Max locked memory 65536 65536 bytes Max pending signals 22028 22028 signals Max msgqueue size 819200 819200 bytes Max nice priority 40 40 Max realtime priority 0 0获取当前打开文件句柄数: /proc/pid/fd 下文件数量
三、崩溃信息
- 崩溃所在线程 ——> ACRA中 THREAD_DETAILS的值
- 崩溃所在Activity ——>