如何以编程方式查找Android应用程序上使用的内存?
我希望有办法做到这一点。此外,我如何获得手机的空闲内存?
如何以编程方式查找Android应用程序上使用的内存?
我希望有办法做到这一点。此外,我如何获得手机的空闲内存?
当前回答
我们发现,获取当前进程总内存的所有标准方法都存在一些问题。
Runtime.getRuntime().totalMemory():仅返回JVM内存ActivityManager.getMemoryInfo()、Process.getFreeMemory()以及基于/proc/meminfo的任何其他内容-返回所有组合进程的内存信息(例如android_util_Process.cpp)Debug.getNativeHeapAllocatedSize()-使用mallinfo(),它只返回malloc()和相关函数执行的内存分配信息(请参阅android_os_Debug.cpp)Debug.getMemoryInfo()-完成了任务,但速度太慢。在Nexus 6上,单次通话大约需要200毫秒。性能开销使得这个函数对我们来说毫无用处,因为我们经常调用它,并且每次调用都非常明显(请参见android_os_Debug.cpp)ActivityManager.getProcessMemoryInfo(int[])-在内部调用Debug.getMemoryInformation()(请参阅ActivityManagerService.java)
最后,我们使用了以下代码:
const long pageSize = 4 * 1024; //`sysconf(_SC_PAGESIZE)`
string stats = File.ReadAllText("/proc/self/statm");
var statsArr = stats.Split(new [] {' ', '\t', '\n'}, 3);
if( statsArr.Length < 2 )
throw new Exception("Parsing error of /proc/self/statm: " + stats);
return long.Parse(statsArr[1]) * pageSize;
它返回VmRSS度量。你可以在这里找到更多关于它的细节:一、二和三。
P.S.我注意到,如果性能不是关键要求,主题仍然缺少一个实际而简单的代码片段,说明如何估计进程的私有内存使用:
Debug.MemoryInfo memInfo = new Debug.MemoryInfo();
Debug.getMemoryInfo(memInfo);
long res = memInfo.getTotalPrivateDirty();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
res += memInfo.getTotalPrivateClean();
return res * 1024L;
其他回答
在android studio 3.0中,他们引入了android profiler,帮助您了解应用程序如何使用CPU、内存、网络和电池资源。
https://developer.android.com/studio/profile/android-profiler
我们发现,获取当前进程总内存的所有标准方法都存在一些问题。
Runtime.getRuntime().totalMemory():仅返回JVM内存ActivityManager.getMemoryInfo()、Process.getFreeMemory()以及基于/proc/meminfo的任何其他内容-返回所有组合进程的内存信息(例如android_util_Process.cpp)Debug.getNativeHeapAllocatedSize()-使用mallinfo(),它只返回malloc()和相关函数执行的内存分配信息(请参阅android_os_Debug.cpp)Debug.getMemoryInfo()-完成了任务,但速度太慢。在Nexus 6上,单次通话大约需要200毫秒。性能开销使得这个函数对我们来说毫无用处,因为我们经常调用它,并且每次调用都非常明显(请参见android_os_Debug.cpp)ActivityManager.getProcessMemoryInfo(int[])-在内部调用Debug.getMemoryInformation()(请参阅ActivityManagerService.java)
最后,我们使用了以下代码:
const long pageSize = 4 * 1024; //`sysconf(_SC_PAGESIZE)`
string stats = File.ReadAllText("/proc/self/statm");
var statsArr = stats.Split(new [] {' ', '\t', '\n'}, 3);
if( statsArr.Length < 2 )
throw new Exception("Parsing error of /proc/self/statm: " + stats);
return long.Parse(statsArr[1]) * pageSize;
它返回VmRSS度量。你可以在这里找到更多关于它的细节:一、二和三。
P.S.我注意到,如果性能不是关键要求,主题仍然缺少一个实际而简单的代码片段,说明如何估计进程的私有内存使用:
Debug.MemoryInfo memInfo = new Debug.MemoryInfo();
Debug.getMemoryInfo(memInfo);
long res = memInfo.getTotalPrivateDirty();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
res += memInfo.getTotalPrivateClean();
return res * 1024L;
哈克堡是堆栈溢出的最佳答案之一。它揭示了一个非常晦涩的主题。这对我帮助很大。
另一个非常有用的资源是这段必看的视频:Google I/O 2011:Android应用程序的内存管理
更新:
Process Stats是一项发现应用程序如何管理内存的服务,Dianne Hackborn在博客文章《Process Stats:了解应用程序如何使用RAM》中对此进行了解释:
我在阅读答案时感到困惑,所以我决定阅读文档。好的,我们来做:
本机堆内存使用情况
您可以使用Debug对象获取设备的本机堆内存大小:
long nativeTotal = Debug.getNativeHeapSize();
long nativeFree = Debug.getNativeHeapFreeSize();
long nativeAllocated = Debug.getNativeHeapAllocatedSize();
long nativeUsed = nativeTotal - nativeFree;
注意:nativeUsed和nativeAllocated具有相同的值。
运行时内存使用
使用应用程序的运行时对象的内存使用情况。每个应用程序都有一个运行时对象来访问其接口:
Runtime runtime = Runtime.getRuntime();
long runtimeMax = runtime.maxMemory();
long runtimeTotal = runtime.totalMemory();
long runtimeFree = runtime.freeMemory();
long runtimeUsed = runtimeTotal - runtimeFree;
系统内存使用
您可以使用ActivityManager.MemoryInfo对象获取系统的内存使用情况:
ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
activityManager.getMemoryInfo(memoryInfo);
long systemTotal = memoryInfo.totalMem;
long systemFree = memoryInfo.availMem;
long systemUsed = systemTotal - systemFree;
过程内存使用
读取系统内存使用情况的另一种方法是在linux中解析/proc/meminfo文件的内容。
RandomAccessFile reader = new RandomAccessFile("/proc/meminfo", "r");
Pattern pattern = Pattern.compile("(\\d+)");
Matcher totalMatcher = pattern.matcher(reader.readLine());
totalMatcher.find();
long procTotal = Long.parseLong(totalMatcher.group(1)) * 1024L; // KB to B
Matcher freeMatcher = pattern.matcher(reader.readLine());
freeMatcher.find();
long procFree = Long.parseLong(freeMatcher.group(1)) * 1024L; // KB to B
long procUsed = procTotal - procFree;
好吧,我还是很困惑。但这是所有可以获得内存使用率的方法。记录它们以调试应用程序!!!
我还为他们每个人提供了一个链接,以阅读他们的用法和信息。
上面有很多答案,肯定会对你有所帮助,但(在对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获取原始数据,这很难存储,因为您需要手动将其分离。
这只是一个尝试,如果我错过了什么,请建议我