如何以编程方式查找Android应用程序上使用的内存?

我希望有办法做到这一点。此外,我如何获得手机的空闲内存?


当前回答

哈克堡是堆栈溢出的最佳答案之一。它揭示了一个非常晦涩的主题。这对我帮助很大。

另一个非常有用的资源是这段必看的视频:Google I/O 2011:Android应用程序的内存管理


更新:

Process Stats是一项发现应用程序如何管理内存的服务,Dianne Hackborn在博客文章《Process Stats:了解应用程序如何使用RAM》中对此进行了解释:

其他回答

是的,您可以通过编程方式获取内存信息,并决定是否执行内存密集型工作。

通过调用获取VM堆大小:

Runtime.getRuntime().totalMemory();

通过调用获取分配的VM内存:

Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();

通过调用获取VM堆大小限制:

Runtime.getRuntime().maxMemory()

通过调用获取本机分配的内存:

Debug.getNativeHeapAllocatedSize();

我制作了一个应用程序来计算OutOfMemoryError行为并监控内存使用情况。

https://play.google.com/store/apps/details?id=net.coocood.oomresearch

您可以在https://github.com/coocood/oom-research

哈克堡是堆栈溢出的最佳答案之一。它揭示了一个非常晦涩的主题。这对我帮助很大。

另一个非常有用的资源是这段必看的视频:Google I/O 2011:Android应用程序的内存管理


更新:

Process Stats是一项发现应用程序如何管理内存的服务,Dianne Hackborn在博客文章《Process Stats:了解应用程序如何使用RAM》中对此进行了解释:

在android studio 3.0中,他们引入了android profiler,帮助您了解应用程序如何使用CPU、内存、网络和电池资源。

https://developer.android.com/studio/profile/android-profiler

上面有很多答案,肯定会对你有所帮助,但(在对adb内存工具进行了2天的负担和研究之后)我想我也可以对我的观点有所帮助。

正如Hackbot所说:因此,如果你将所有实际映射到每个进程中的物理RAM相加,你可能会得到一个比实际总RAM大得多的数字。因此,无法获得每个进程的确切内存量。

但你可以通过某种逻辑接近它。。我会告诉你。。

有一些API,如上面提到的android.os.Debug.MemoryInfo和ActivityManager.getMemoryInfo(),您可能已经阅读并使用了这些API,但我将讨论其他方式

因此,首先你需要成为一个根用户才能让它工作。通过在进程中执行su,以root权限进入控制台,并获取其输出和输入流。然后在输出流中传递id\n(enter)并将其写入进程输出。如果将获得包含uid=0的输入流,则表示您是root用户。

下面是您将在上述过程中使用的逻辑

当您获得进程的输出流时,请使用命令(procrank、dumpsys meminfo等…)而不是id,并获取其输入流并读取,以字节[]、字符[]等形式存储流。使用原始数据。。你完成了!!!!!

许可:

<uses-permission android:name="android.permission.FACTORY_TEST"/>

检查您是否为root用户:

// su command to get root access
Process process = Runtime.getRuntime().exec("su");         
DataOutputStream dataOutputStream = 
                           new DataOutputStream(process.getOutputStream());
DataInputStream dataInputStream = 
                           new DataInputStream(process.getInputStream());
if (dataInputStream != null && dataOutputStream != null) {
   // write id to console with enter
   dataOutputStream.writeBytes("id\n");                   
   dataOutputStream.flush();
   String Uid = dataInputStream.readLine();
   // read output and check if uid is there
   if (Uid.contains("uid=0")) {                           
      // you are root user
   } 
}

使用su执行命令

Process process = Runtime.getRuntime().exec("su");         
DataOutputStream dataOutputStream = 
                           new DataOutputStream(process.getOutputStream());
if (dataOutputStream != null) {
 // adb command
 dataOutputStream.writeBytes("procrank\n");             
 dataOutputStream.flush();
 BufferedInputStream bufferedInputStream = 
                     new BufferedInputStream(process.getInputStream());
 // this is important as it takes times to return to next line so wait
 // else you with get empty bytes in buffered stream 
 try {
       Thread.sleep(10000);
 } catch (InterruptedException e) {                     
       e.printStackTrace();
 }
 // read buffered stream into byte,char etc.
 byte[] bff = new byte[bufferedInputStream.available()];
 bufferedInputStream.read(bff);
 bufferedInputStream.close();
 }
}

日志目录:

您可以从控制台获取单个字符串中的原始数据,而不是在某些情况下从任何API获取原始数据,这很难存储,因为您需要手动将其分离。

这只是一个尝试,如果我错过了什么,请建议我

这是一项正在进行的工作,但我不明白:

ActivityManager activityManager = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE);
MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
activityManager.getMemoryInfo(memoryInfo);

Log.i(TAG, " memoryInfo.availMem " + memoryInfo.availMem + "\n" );
Log.i(TAG, " memoryInfo.lowMemory " + memoryInfo.lowMemory + "\n" );
Log.i(TAG, " memoryInfo.threshold " + memoryInfo.threshold + "\n" );

List<RunningAppProcessInfo> runningAppProcesses = activityManager.getRunningAppProcesses();

Map<Integer, String> pidMap = new TreeMap<Integer, String>();
for (RunningAppProcessInfo runningAppProcessInfo : runningAppProcesses)
{
    pidMap.put(runningAppProcessInfo.pid, runningAppProcessInfo.processName);
}

Collection<Integer> keys = pidMap.keySet();

for(int key : keys)
{
    int pids[] = new int[1];
    pids[0] = key;
    android.os.Debug.MemoryInfo[] memoryInfoArray = activityManager.getProcessMemoryInfo(pids);
    for(android.os.Debug.MemoryInfo pidMemoryInfo: memoryInfoArray)
    {
        Log.i(TAG, String.format("** MEMINFO in pid %d [%s] **\n",pids[0],pidMap.get(pids[0])));
        Log.i(TAG, " pidMemoryInfo.getTotalPrivateDirty(): " + pidMemoryInfo.getTotalPrivateDirty() + "\n");
        Log.i(TAG, " pidMemoryInfo.getTotalPss(): " + pidMemoryInfo.getTotalPss() + "\n");
        Log.i(TAG, " pidMemoryInfo.getTotalSharedDirty(): " + pidMemoryInfo.getTotalSharedDirty() + "\n");
    }
}

为什么PID没有映射到activityManager.getProcessMemoryInfo()中的结果?很明显,你想让结果数据变得有意义,那么为什么谷歌会让结果之间的关联变得如此困难呢?如果我想处理整个内存使用情况,当前系统甚至无法正常工作,因为返回的结果是一个android.os.Debug.MemoryInfo对象数组,但这些对象都没有告诉你它们与哪些pid相关。如果只传入所有pid的数组,则无法理解结果。据我所知,一次传递多个pid是没有意义的,如果是这样,为什么要使activityManager.getProcessMemoryInfo()只接受一个int数组?