Recuperar mediante programación el uso de memoria en iPhone
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.
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.
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 Swift
versiones.
Aquí se explica cómo obtener el valor esperado escrito por Quinn “The Eskimo!” de Apple.
Esto utiliza la phys_footprint
var de Darwin > Mach > task_info
y 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 usedMBAsString
solo devuelva 2 decimales significativos.