Recuperar mediante programación el uso de memoria en iPhone

Resuelto Coocoo4Cocoa asked hace 54 años • 8 respuestas

Estoy intentando recuperar la cantidad de memoria que usa mi aplicación de iPhone en cualquier momento, mediante programación. Sí, conozco ObjectAlloc/Leaks. No estoy interesado en eso, solo quiero saber si es posible escribir algún código y obtener la cantidad de bytes que se utilizan e informarlo a través de NSLog.

Gracias.

Coocoo4Cocoa avatar Jan 01 '70 08:01 Coocoo4Cocoa
Aceptado

Para obtener los bytes reales de memoria que utiliza su aplicación, puede hacer algo como el siguiente ejemplo. Sin embargo, realmente debería familiarizarse con las diversas herramientas de creación de perfiles, ya que están diseñadas para brindarle una idea mucho mejor del uso en general.

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

También hay un campo en la estructura info.virtual_size que le dará la cantidad de bytes de memoria virtual disponibles (o memoria asignada a su aplicación como memoria virtual potencial en cualquier caso). El código al que se vincula pgb le dará la cantidad de memoria disponible para el dispositivo y qué tipo de memoria es.

Jason Coco avatar Apr 24 '2009 20:04 Jason Coco

Esto se probó en Xcode 11 en Mojave 10.4.6 el 01/07/2019 y en Xcode 11.3 a partir del 05/11/2020.

Todas las respuestas anteriores arrojan resultados incorrectos .

A continuación se muestran dos Swiftversiones.

Aquí se explica cómo obtener el valor esperado escrito por Quinn “The Eskimo!” de Apple.

Esto utiliza la phys_footprintvar de Darwin > Mach > task_infoy coincide estrechamente con el valor en el indicador de memoria en el navegador de depuración de Xcode .

El valor devuelto está en bytes.

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

A continuación se muestra el código original.

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  
}  

Modificar esto ligeramente para crear un conjunto de métodos Swift a nivel de clase permite un fácil retorno de los bytes reales y la salida formateada en MB para su visualización. Utilizo esto como parte de una suite UITest automatizada para registrar la memoria utilizada antes y después de múltiples iteraciones de la misma prueba para ver si tenemos posibles fugas o asignaciones que debamos investigar.

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

¡Disfrutar!

Nota: un codificador emprendedor puede querer agregar un formateador estático a la clase para que usedMBAsStringsolo devuelva 2 decimales significativos.

Alex Zavatone avatar Aug 01 '2019 19:08 Alex Zavatone