Categories
cocoa-touch ios iphone memory objective-c

Programmatically retrieve memory usage on iPhone

112

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.

0

    137

    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.

    17

    • 4

      thanks, exactly what I was searching for. Is this method app store safe?

      – Buju

      Jul 4, 2011 at 13:02

    • 3

      If you Cmd+Click task_basic_info, it seems that this should now not be used and replaced with mach_task_basic_info. My guess is that this version is not compatible with 64-bit architecture, but not really sure.

      – cprcrack

      Oct 30, 2013 at 18:16

    • 17

      In my case, the amount returned is over twice as much as the memory report in XCode puts out. Not sure what to make of it.

      – Morkrom

      Jan 16, 2014 at 19:43

    • 1

      How to get the memory usage by other applications?

      Jul 29, 2015 at 6:03

    • 2

      @Morkrom have you figured out why? I have the same problem around twice bigger running simulator and almost 3 times on a device.

      – Julian

      Oct 6, 2015 at 7:56

    42

    This has been tested on Xcode 11 in Mojave 10.4.6 on 07/01/2019, and on Xcode 11.3 as of 11/05/2020

    All of the previous answers return the incorrect result.

    Two Swift versions are below.

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

    This uses the phys_footprint var from Darwin > Mach > task_info and closely matches the value in the memory gauge in Xcode’s Debug navigator.

    The value returned is in bytes.

    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.

    //  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 usedMBAsString only returns 2 significant decimal places.

    1

    • 1

      This should really be the accepted answer (as an example; only solution for NEPacketTunnelProvider extension).

      Oct 14, 2021 at 5:54


    32

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

    8

    • Any idea why the value logged here is around twice bigger on a simulator than Xcode reports and three times on a real device?

      – Julian

      Oct 6, 2015 at 7:57

    • 1

      I don’t know why the difference. That would make a good new question.

      Oct 6, 2015 at 16:47

    • 1

      I found the difference. It is because of resident memory not the live bytes

      – Julian

      Oct 6, 2015 at 17:16

    • can we get memory usage of other applications?? @combinatorial

      Dec 23, 2015 at 11:03

    • 1

      @VikasBansal no you can’t.

      Dec 23, 2015 at 15:21