iOS 获取设备占用内存,剩余内存
Posted 想名真难
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS 获取设备占用内存,剩余内存相关的知识,希望对你有一定的参考价值。
获取应用占用内存
#import <mach/mach.h>
- (int64_t)memoryUsage
int64_t memoryUsageInByte = 0;
struct task_basic_info taskBasicInfo;
mach_msg_type_number_t size = sizeof(taskBasicInfo);
kern_return_t kernelReturn = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t) &taskBasicInfo, &size);
if(kernelReturn == KERN_SUCCESS)
memoryUsageInByte = (int64_t) taskBasicInfo.resident_size;
NSLog(@"Memory in use (in bytes): %lld", memoryUsageInByte);
else
NSLog(@"Error with task_info(): %s", mach_error_string(kernelReturn));
return memoryUsageInByte;
使用时发现这个和Xcode中大小不一致,在正确地获取 iOS 应用占用的内存文章中介绍的phys_footprint
获取方式更接近。
#import <mach/mach.h>
- (int64_t)memoryUsage
int64_t memoryUsageInByte = 0;
task_vm_info_data_t vmInfo;
mach_msg_type_number_t count = TASK_VM_INFO_COUNT;
kern_return_t kernelReturn = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t) &vmInfo, &count);
if(kernelReturn == KERN_SUCCESS)
memoryUsageInByte = (int64_t) vmInfo.phys_footprint;
NSLog(@"Memory in use (in bytes): %lld", memoryUsageInByte);
else
NSLog(@"Error with task_info(): %s", mach_error_string(kernelReturn));
return memoryUsageInByte;
补充:
在腾讯的OOMDetector内存检测组件中使用的是第一种方式,在Issues中app使用内存计算的与xcode计算的不一致问题中介绍说:ios有memory compress机制,所以实际占用的物理内存会比app分配的内存少。
但是本人在项目中更倾向于使用第二种获取方式。
系统总内存空间
+ (int64_t)getTotalMemory
int64_t totalMemory = [[NSProcessInfo processInfo] physicalMemory];
if (totalMemory < -1) totalMemory = -1;
return totalMemory;
物理内存页面的生命周期状态
-
Free
空闲,物理页没被任何虚拟内存使用,未使用的 RAM 容量,随时可以被应用分配使用。 -
Active
活跃,物理页正用于一个虚拟内存页,并且最近被引用过,这种页面一般不会被交换出去 -
Inactive
非活跃,物理页正用于一个虚拟内存页,但最近没有被引用过,这种页面有可能被交换出去 -
Speculative
投机,对可能的内存需求做了一个猜测是的内存分配(不是活跃状态也不是非活跃状态,有可能马上被访问),对页面进行投机映射,因为很可能很快被访问到 -
Wired down
联动,物理页正用于一个虚拟内存页,但该页面被锁定,不能交换,一般用于内核代码数据,用来存放内核代码和数据结构,它主要为内核服务,如负责网络、文件系统之类的;对于应用、framework、一些用户级别的软件是没办法分配此内存的。但是应用程序也会对 Wired Memory 的分配有所影响。 -
Purgeable
可以理解为可释放的内存,主要是大对象或大内存块才可以使用的内存,此内存会在内存紧张的时候自动释放掉。
// 活跃的内存,正在使用或者很短时间内被使用过:已使用,但可被分页的(在iOS中,只有在磁盘上静态存在的才能被分页,例如文件的内存映射,而动态分配的内存是不能被分页的)
+ (int64_t)getActiveMemory
mach_port_t host_port = mach_host_self();
mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
vm_size_t page_size;
vm_statistics_data_t vm_stat;
kern_return_t kern;
kern = host_page_size(host_port, &page_size);
if (kern != KERN_SUCCESS) return -1;
kern = host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size);
if (kern != KERN_SUCCESS) return -1;
return vm_stat.active_count * page_size;
// 最近使用过,但是目前处于不活跃状态的内存:程序退出后却没释放的内存,以便加快再次启动,而当内存不足时,就会被回收,因此也可看作空闲内存
+ (int64_t)getInActiveMemory
mach_port_t host_port = mach_host_self();
mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
vm_size_t page_size;
vm_statistics_data_t vm_stat;
kern_return_t kern;
kern = host_page_size(host_port, &page_size);
if (kern != KERN_SUCCESS) return -1;
kern = host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size);
if (kern != KERN_SUCCESS) return -1;
return vm_stat.inactive_count * page_size;
// 用来存放内核和数据结构的内存,framework、用户级别的应用无法分配
+ (int64_t)getWiredMemory
mach_port_t host_port = mach_host_self();
mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
vm_size_t page_size;
vm_statistics_data_t vm_stat;
kern_return_t kern;
kern = host_page_size(host_port, &page_size);
if (kern != KERN_SUCCESS) return -1;
kern = host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size);
if (kern != KERN_SUCCESS) return -1;
return vm_stat.wire_count * page_size;
// 已使用的内存空间
+ (int64_t)getUsedMemory
mach_port_t host_port = mach_host_self();
mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
vm_size_t page_size;
vm_statistics_data_t vm_stat;
kern_return_t kern;
kern = host_page_size(host_port, &page_size);
if (kern != KERN_SUCCESS) return -1;
kern = host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size);
if (kern != KERN_SUCCESS) return -1;
return page_size * (vm_stat.active_count + vm_stat.inactive_count + vm_stat.wire_count);
// 空闲的内存空间,:未使用的 RAM 容量,随时可以被应用分配使用。(感觉本方法和腾讯bugly崩溃统计中的可用内存大小相似)
+ (int64_t)getFreeMemory
mach_port_t host_port = mach_host_self();
mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
vm_size_t page_size;
vm_statistics_data_t vm_stat;
kern_return_t kern;
kern = host_page_size(host_port, &page_size);
if (kern != KERN_SUCCESS) return -1;
kern = host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size);
if (kern != KERN_SUCCESS) return -1;
return vm_stat.free_count * page_size;
// 可释放的内存空间:内存吃紧自动释放,针对大对象存放所需的大块内存空间
+ (int64_t)getPurgableMemory
mach_port_t host_port = mach_host_self();
mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
vm_size_t page_size;
vm_statistics_data_t vm_stat;
kern_return_t kern;
kern = host_page_size(host_port, &page_size);
if (kern != KERN_SUCCESS) return -1;
kern = host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size);
if (kern != KERN_SUCCESS) return -1;
return vm_stat.purgeable_count * page_size;
获取当前可用内存
vm_statistics_data_t结构体中,free是空闲内存;
active是已使用,但可被分页的(在iOS中,只有在磁盘上静态存在的才能被分页,例如文件的内存映射,而动态分配的内存是不能被分页的);
inactive是不活跃的,也就是程序退出后却没释放的内存,以便加快再次启动,而当内存不足时,就会被回收,因此也可看作空闲内存;
wire就是已使用,且不可被分页的。
网上大部分的获取是这样的, 但是实测和xcode的有差别.
// 获取当前可用内存
+ (long long)getAvailableMemorySize
vm_statistics_data_t vmStats;
mach_msg_type_number_t infoCount = HOST_VM_INFO_COUNT;
kern_return_t kernReturn = host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&vmStats, &infoCount);
if (kernReturn != KERN_SUCCESS)
return NSNotFound;
return ((vm_page_size * vmStats.free_count + vm_page_size * vmStats.inactive_count));
下面的这种和xcode获取的最接近, 所以更推荐用下面这个.
空闲内存看成总内存大小减去 Wired Memory大小,Active Memory大小以及Inactive Memory大小。在32位系统通过这种方式获取空闲内存与Xcode数据作比较误差范围较小,而在64位系统上的数据与Xcode数据一比较误差较大,同样找到一个逆向Xcode获取Xcode的计算内存方法。64位系统获取空闲内存的具体代码如下:
// 基于原文写法优化,把无效的计算去掉了
+ (double)usageComparisonFree
mach_port_t host_port = mach_host_self();
mach_msg_type_number_t count = HOST_VM_INFO64_COUNT;
vm_size_t page_size;
vm_statistics64_data_t vminfo;
host_page_size(host_port, &page_size);
host_statistics64(host_port, HOST_VM_INFO64, (host_info64_t)&vminfo,&count);
uint64_t free_size = (vminfo.free_count + vminfo.external_page_count + vminfo.purgeable_count - vminfo.speculative_count) * page_size;
return free_size / 1024.0 / 1024.0;
// 原文的写法,备份
+ (double)usageComparisonFree
int64_t physical_memory = [[NSProcessInfo processInfo] physicalMemory];
mach_port_t host_port = mach_host_self();
mach_msg_type_number_t count = HOST_VM_INFO64_COUNT;
vm_size_t page_size;
vm_statistics64_data_t vminfo;
host_page_size(host_port, &page_size);
host_statistics64(host_port, HOST_VM_INFO64, (host_info64_t)&vminfo,&count);
uint64_t total_used_count = (physical_memory /page_size) - (vminfo.free_count - vminfo.speculative_count) - vminfo.external_page_count - vminfo.purgeable_count;
uint64_t free_size = ((physical_memory / page_size) -total_used_count) * page_size;
return free_size / 1024.0 / 1024.0;
以上是关于iOS 获取设备占用内存,剩余内存的主要内容,如果未能解决你的问题,请参考以下文章