Programmatically retrieve memory usage on iPhone

2018-12-31 18:21发布

问题:

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.

Thanks.

回答1:

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 = sizeof(info);
  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 MB): %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.



回答2:

The headers forTASK_BASIC_INFO say:

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

Here is a version using 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));
    }
}


回答3:

Here is report_memory() enhanced to rapidly show leak status in the 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;
}


回答4:

Swift solution of Jason Coco\'s answer:

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))\")
    }
}


回答5:

Swift 3.1 (As of August 8, 2017)

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) {
        $0.withMemoryRebound(to: integer_t.self, capacity: 1) {
            task_info(mach_task_self_, task_flavor_t(MACH_TASK_BASIC_INFO), $0, &count)
        }
    }
    if kerr == KERN_SUCCESS {
        let usedMegabytes = taskInfo.resident_size/1000000
        print(\"used megabytes: \\(usedMegabytes)\")
    } else {
        print(\"Error with task_info(): \" +
            (String(cString: mach_error_string(kerr), encoding: String.Encoding.ascii) ?? \"unknown error\"))
    }

}


回答6:

Here\'s a Swift 3 Version:

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


回答7:

Below is the correct answer:

```

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

```