以编程方式在iOS应用程序中获取内存使用实时/脏字节(不是驻留/实际字节)
根据我到目前为止所读到的内容,实际/驻留字节表示分配给应用程序的字节数,包括应用程序不再使用但尚未被操作系统回收的字节数。 实时/脏字节是应用实际使用的字节数,操作系统无法回收。 我认为XCode Debug导航器中显示的数字是Live Bytes。
我有兴趣以编程方式获取此数字(对于我们自己的统计/分析),但我找到的代码只能给出驻留字节的值,这大于Xcode在某些设备上显示的值(几乎两倍大) ),实际上在相同的设备上但不同的iOS版本。 (在iOS 9上,它的值几乎是其两倍,但在iOS 11上它提供的值几乎与Xcode相同)。
我使用的代码是这样的:
struct mach_task_basic_info info; mach_msg_type_number_t size = MACH_TASK_BASIC_INFO_COUNT; kern_return_t kerr = task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &size); if( kerr == KERN_SUCCESS ) { NSLog(@"Memory in use (in bytes): %u", info.resident_size); return info.resident_size; } else { NSLog(@"Error with task_info(): %s", mach_error_string(kerr)); }
是否有一些代码来获取Xcode显示的实时字节值?
我发现了其他的东西,但它似乎在设备上工作,以前的方法不起作用,并没有在上一个方法确实工作的设备上工作:-(现在我需要弄清楚如何知道使用哪一个。一台设备是带有iOS 9的iPhone 5s,另一台是带有iOS 11的iPhone 5s。我想我需要测试更多的设备…
我在这里找到了:
https://opensource.apple.com/source/WebKit/WebKit-7603.1.30.1.33/ios/Misc/MemoryMeasure.mm.auto.html
这在Objective-C中翻译成类似的东西:
task_vm_info_data_t vmInfo; mach_msg_type_number_t count = TASK_VM_INFO_COUNT; kern_return_t err = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t) &vmInfo, &count); if (err != KERN_SUCCESS) return 0; NSLog(@"Memory in use vmInfo.internal (in bytes): %u", vmInfo.internal); return vmInfo.internal;
我想如果我添加vmInfo.internal和vmInfo.compressed,那么我将得到正确的结果(匹配Xcode Debug导航器显示的内容)
到目前为止,这两个设备看起来是正确的,还有我测试的其他两个设备。
所以我的最终代码如下所示:
task_vm_info_data_t info; mach_msg_type_number_t size = TASK_VM_INFO_COUNT; kern_return_t kerr = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t)&info, &size); if( kerr == KERN_SUCCESS ) { mach_vm_size_t totalSize = info.internal + info.compressed; NSLog(@"Memory in use (in bytes): %u", totalSize); return totalSize; } else { NSLog(@"Error with task_info(): %s", mach_error_string(kerr)); }
这是Alex的解决方案的Swift 3版本:
let TASK_VM_INFO_COUNT = MemoryLayout.size / MemoryLayout.size var vmInfo = task_vm_info_data_t() var vmInfoSize = mach_msg_type_number_t(TASK_VM_INFO_COUNT) let kern: kern_return_t = withUnsafeMutablePointer(to: &vmInfo) { $0.withMemoryRebound(to: integer_t.self, capacity: 1) { task_info(mach_task_self_, task_flavor_t(TASK_VM_INFO), $0, &vmInfoSize) } } if kern == KERN_SUCCESS { let usedSize = DataSize(bytes: Int(vmInfo.internal + vmInfo.compressed)) print("Memory in use (in bytes): %u", usedSize) } else { let errorString = String(cString: mach_error_string(kern), encoding: .ascii) ?? "unknown error" print("Error with task_info(): %s", errorString); }
此代码基于与mach_task_basic_info
和resident_size
类似的答案 。