ios 以编程方式检索 iPhone 上的内存使用情况

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/787160/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 15:50:09  来源:igfitidea点击:

Programmatically retrieve memory usage on iPhone

iosobjective-ciphonecocoa-touchmemory

提问by Coocoo4Cocoa

I'm trying to retrieve the amount of memory my iPhone app is using at anytime, programmatically. Yes I'm aware about ObjectAlloc/Leaks. I'm not interested in those, only to know if it's possible to write some code and get the amount of bytes being used and report it via NSLog.

我正在尝试以编程方式随时检索我的 iPhone 应用程序正在使用的内存量。是的,我知道 ObjectAlloc/Leaks。我对这些不感兴趣,只是想知道是否可以编写一些代码并获取正在使用的字节数并通过 NSLog 报告它。

Thanks.

谢谢。

回答by Jason Coco

To get the actual bytes of memory that your application is using, you can do something like the example below. However, you really should become familiar with the various profiling tools as well as they are designed to give you a much better picture of usage over-all.

要获取您的应用程序正在使用的实际内存字节,您可以执行类似于以下示例的操作。但是,您确实应该熟悉各种分析工具,它们旨在让您更好地了解总体使用情况。

#import <mach/mach.h>

// ...

void report_memory(void) {
  struct task_basic_info info;
  mach_msg_type_number_t size = TASK_BASIC_INFO_COUNT;
  kern_return_t kerr = task_info(mach_task_self(),
                                 TASK_BASIC_INFO,
                                 (task_info_t)&info,
                                 &size);
  if( kerr == KERN_SUCCESS ) {
    NSLog(@"Memory in use (in bytes): %lu", info.resident_size);
    NSLog(@"Memory in use (in MiB): %f", ((CGFloat)info.resident_size / 1048576));
  } else {
    NSLog(@"Error with task_info(): %s", mach_error_string(kerr));
  }
}

There is also a field in the structure info.virtual_size which will give you the number of bytes available virtual memory (or memory allocated to your application as potential virtual memory in any event). The code that pgb links to will give you the amount of memory available to the device and what type of memory it is.

结构 info.virtual_size 中还有一个字段,它将为您提供可用虚拟内存的字节数(或在任何情况下作为潜在虚拟内存分配给您的应用程序的内存)。pgb 链接到的代码将为您提供设备可用的内存量以及它是什么类型的内存。

回答by combinatorial

The headers forTASK_BASIC_INFOsay:

标题TASK_BASIC_INFO说:

/* Don't use this, use MACH_TASK_BASIC_INFO instead */

Here is a version using MACH_TASK_BASIC_INFO:

这是一个使用的版本MACH_TASK_BASIC_INFO

void report_memory(void)
{
    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);
    } else {
        NSLog(@"Error with task_info(): %s", mach_error_string(kerr));
    }
}

回答by Doug Null

Here is report_memory() enhanced to rapidly show leak status in the NSLog().

这是 report_memory() 增强以快速显示 NSLog() 中的泄漏状态。

void report_memory(void) {
    static unsigned last_resident_size=0;
    static unsigned greatest = 0;
    static unsigned last_greatest = 0;

    struct task_basic_info info;
    mach_msg_type_number_t size = sizeof(info);
    kern_return_t kerr = task_info(mach_task_self(),
                               TASK_BASIC_INFO,
                               (task_info_t)&info,
                               &size);
    if( kerr == KERN_SUCCESS ) {
        int diff = (int)info.resident_size - (int)last_resident_size;
        unsigned latest = info.resident_size;
        if( latest > greatest   )   greatest = latest;  // track greatest mem usage
        int greatest_diff = greatest - last_greatest;
        int latest_greatest_diff = latest - greatest;
        NSLog(@"Mem: %10u (%10d) : %10d :   greatest: %10u (%d)", info.resident_size, diff,
          latest_greatest_diff,
          greatest, greatest_diff  );
    } else {
        NSLog(@"Error with task_info(): %s", mach_error_string(kerr));
    }
    last_resident_size = info.resident_size;
    last_greatest = greatest;
}

回答by Alex Zavatone

This has been tested on Xcode 11 in Mojave 10.4.6 on 07/01/2019.

这已于 2019 年 7 月 1 日在 Mojave 10.4.6 中的 Xcode 11 上进行了测试。

All of the previous answers return the incorrect result.

之前的所有答案都返回错误的结果

Here is how to get the expected value written by Apple's Quinn “The Eskimo!”.

下面是如何得到苹果的奎因“爱斯基摩人!”所写的期望值。

This uses the phys_footprintvar from Darwin > Mach > task_infoand closely matches the value in the memory gauge in Xcode's Debug navigator.

这使用phys_footprintvar fromDarwin > Mach > task_info与 Xcode 的 Debug navigator 中内存量规中的值紧密匹配

The value returned is in bytes.

返回值以字节为单位。

https://forums.developer.apple.com/thread/105088#357415

https://forums.developer.apple.com/thread/105088#357415

Original code follows.

原始代码如下。

func memoryFootprint() -> mach_vm_size_t? {  
    // The `TASK_VM_INFO_COUNT` and `TASK_VM_INFO_REV1_COUNT` macros are too  
    // complex for the Swift C importer, so we have to define them ourselves.  
    let TASK_VM_INFO_COUNT = mach_msg_type_number_t(MemoryLayout<task_vm_info_data_t>.size / MemoryLayout<integer_t>.size)  
    let TASK_VM_INFO_REV1_COUNT = mach_msg_type_number_t(MemoryLayout.offset(of: \task_vm_info_data_t.min_address)! / MemoryLayout<integer_t>.size)  
    var info = task_vm_info_data_t()  
    var count = TASK_VM_INFO_COUNT  
    let kr = withUnsafeMutablePointer(to: &info) { infoPtr in  
        infoPtr.withMemoryRebound(to: integer_t.self, capacity: Int(count)) { intPtr in  
            task_info(mach_task_self_, task_flavor_t(TASK_VM_INFO), intPtr, &count)  
        }  
    }  
    guard  
        kr == KERN_SUCCESS,  
        count >= TASK_VM_INFO_REV1_COUNT  
    else { return nil }  
    return info.phys_footprint  
}  

Modifying this slightly to create a class level set of Swift methods allows easy return of the actual bytes and formatted output in MB for display. I use this as part of an automated UITest suite to log memory used before and after multiple iterations of the same test to see if we have any potential leaks or allocations we need to look into.

稍微修改它以创建一个类级别的 Swift 方法集,可以轻松返回实际字节和以 MB 为单位的格式化输出以供显示。我使用它作为自动化 UITest 套件的一部分来记录在同一测试的多次迭代之前和之后使用的内存,以查看我们是否有任何需要调查的潜在泄漏或分配。

//  Created by Alex Zavatone on 8/1/19.
//

class Memory: NSObject {

    // From Quinn the Eskimo at Apple.
    // https://forums.developer.apple.com/thread/105088#357415

    class func memoryFootprint() -> Float? {
        // The `TASK_VM_INFO_COUNT` and `TASK_VM_INFO_REV1_COUNT` macros are too
        // complex for the Swift C importer, so we have to define them ourselves.
        let TASK_VM_INFO_COUNT = mach_msg_type_number_t(MemoryLayout<task_vm_info_data_t>.size / MemoryLayout<integer_t>.size)
        let TASK_VM_INFO_REV1_COUNT = mach_msg_type_number_t(MemoryLayout.offset(of: \task_vm_info_data_t.min_address)! / MemoryLayout<integer_t>.size)
        var info = task_vm_info_data_t()
        var count = TASK_VM_INFO_COUNT
        let kr = withUnsafeMutablePointer(to: &info) { infoPtr in
            infoPtr.withMemoryRebound(to: integer_t.self, capacity: Int(count)) { intPtr in
                task_info(mach_task_self_, task_flavor_t(TASK_VM_INFO), intPtr, &count)
            }
        }
        guard
            kr == KERN_SUCCESS,
            count >= TASK_VM_INFO_REV1_COUNT
            else { return nil }

        let usedBytes = Float(info.phys_footprint)
        return usedBytes
    }

    class func formattedMemoryFootprint() -> String
    {
        let usedBytes: UInt64? = UInt64(self.memoryFootprint() ?? 0)
        let usedMB = Double(usedBytes ?? 0) / 1024 / 1024
        let usedMBAsString: String = "\(usedMB)MB"
        return usedMBAsString
     }
}

Enjoy!

享受!

Note: an enterprising coder may want to add a static formatter to the class so that usedMBAsStringonly returns 2 significant decimal places.

注意:有进取心的编码人员可能希望向类添加静态格式化程序,以便usedMBAsString仅返回 2 个有效小数位。

回答by Nazariy Vlizlo

Swift solution of Jason Coco's answer:

Jason Coco的答案的Swift 解决方案:

func reportMemory() {
    let name = mach_task_self_
    let flavor = task_flavor_t(TASK_BASIC_INFO)
    let basicInfo = task_basic_info()
    var size: mach_msg_type_number_t = mach_msg_type_number_t(sizeofValue(basicInfo))
    let pointerOfBasicInfo = UnsafeMutablePointer<task_basic_info>.alloc(1)

    let kerr: kern_return_t = task_info(name, flavor, UnsafeMutablePointer(pointerOfBasicInfo), &size)
    let info = pointerOfBasicInfo.move()
    pointerOfBasicInfo.dealloc(1)

    if kerr == KERN_SUCCESS {
        print("Memory in use (in bytes): \(info.resident_size)")
    } else {
        print("error with task info(): \(mach_error_string(kerr))")
    }
}

回答by BennyTheNerd

Swift 3.1(As of August 8, 2017)

Swift 3.1 (截至 2017 年 8 月 8 日)

func getMemory() {

    var taskInfo = mach_task_basic_info()
    var count = mach_msg_type_number_t(MemoryLayout<mach_task_basic_info>.size)/4
    let kerr: kern_return_t = withUnsafeMutablePointer(to: &taskInfo) {
        
func mach_task_self() -> task_t {
    return mach_task_self_
}

func getMegabytesUsed() -> Float? {
    var info = mach_task_basic_info()
    var count = mach_msg_type_number_t(MemoryLayout.size(ofValue: info) / MemoryLayout<integer_t>.size)
    let kerr = withUnsafeMutablePointer(to: &info) { infoPtr in
        return infoPtr.withMemoryRebound(to: integer_t.self, capacity: Int(count)) { (machPtr: UnsafeMutablePointer<integer_t>) in
            return task_info(
                mach_task_self(),
                task_flavor_t(MACH_TASK_BASIC_INFO),
                machPtr,
                &count
            )
        }
    }
    guard kerr == KERN_SUCCESS else {
        return nil
    }  
    return Float(info.resident_size) / (1024 * 1024)   
}
.withMemoryRebound(to: integer_t.self, capacity: 1) { task_info(mach_task_self_, task_flavor_t(MACH_TASK_BASIC_INFO),
size_t memoryFootprint()
{
    task_vm_info_data_t vmInfo;
    mach_msg_type_number_t count = TASK_VM_INFO_COUNT;
    kern_return_t result = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t) &vmInfo, &count);
    if (result != KERN_SUCCESS)
        return 0;
    return static_cast<size_t>(vmInfo.phys_footprint);
}
, &count) } } if kerr == KERN_SUCCESS { let usedMegabytes = taskInfo.resident_size/(1024*1024) print("used megabytes: \(usedMegabytes)") } else { print("Error with task_info(): " + (String(cString: mach_error_string(kerr), encoding: String.Encoding.ascii) ?? "unknown error")) } }

回答by jeffbailey

Here's a Swift 3 Version:

这是一个 Swift 3 版本:

float GetTotalPhysicsMemory()
{
    struct task_basic_info info;
    mach_msg_type_number_t size = sizeof(info);
    kern_return_t kr;
    kr = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &size);
    if (kr == KERN_SUCCESS) 
        return (float)(info.resident_size) / 1024.0 / 1024.0;
    else
        return 0;
}

回答by Jimmy Yin

回答by rensq

Below is the correct answer:

下面是正确答案:

```

``

##代码##

```

``