【问题标题】:Getting memory usage Live/Dirty Bytes in iOS app programmatically (not Resident/Real Bytes)以编程方式获取 iOS 应用程序中的内存使用 Live/Dirty Bytes(不是 Resident/Real Bytes)
【发布时间】:2018-02-26 14:32:41
【问题描述】:

根据我目前所读到的内容,实际/驻留字节表示分配给应用程序的字节数,包括应用程序不再使用但操作系统尚未回收的字节数。 实时/脏字节是应用程序实际使用的字节,操作系统无法回收。 我认为 XCode Debug navigator 中显示的数字是 Live Bytes。

我有兴趣以编程方式获取这个数字(用于我们自己的统计/分析),但我发现的代码只能给出驻留字节的值,它大于 Xcode 在某些设备上显示的值(几乎两次很大),实际上在相同的设备上但不同的 iOS 版本。 (在 iOS 9 上,它给出的值几乎是 Xcode 的两倍,但在 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 xcode memory memory-profiling


    【解决方案1】:

    我发现了其他东西,但它似乎在以前的方法不起作用的设备上工作,并且在以前的方法工作的设备上不起作用:-( 现在我需要弄清楚如何知道使用哪一个。一台设备是装有 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 navigator 显示的内容)

    到目前为止,这两款设备以及我测试的其他 2 台设备看起来都不错。

    所以我的最终代码如下所示:

    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));
    }
    

    【讨论】:

    • 谢谢!似乎也适用于 macOS(在 macOS 10.12.6、Sierra 上验证)。
    【解决方案2】:

    由于在 Obj-C 和 Swift 中对 Darwin 类型的访问看起来略有不同,我想添加我在 Swift 中基于Alex's answer 提出的解决方案:

    let TASK_VM_INFO_COUNT = MemoryLayout<task_vm_info_data_t>.size / MemoryLayout<natural_t>.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);
    }
    

    此代码基于类似的answermach_task_basic_inforesident_size

    【讨论】:

    • 感谢 swift 版本,这确实有效。不知道在哪里可以找到关于 task_info 的文档,因为苹果什么也没说。
    猜你喜欢
    • 2013-09-01
    • 1970-01-01
    • 2013-06-22
    • 2011-12-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多