Mengambil penggunaan memori secara terprogram di iPhone

101

Saya mencoba mengambil kembali jumlah memori yang digunakan aplikasi iPhone saya kapan saja, secara terprogram. Ya, saya mengetahui tentang ObjectAlloc / Leaks. Saya tidak tertarik dengan itu, hanya untuk mengetahui apakah mungkin untuk menulis beberapa kode dan mendapatkan jumlah byte yang digunakan dan melaporkannya melalui NSLog.

Terima kasih.

Coocoo4Cocoa
sumber
Sobat, saya sudah berhasil mendapatkan kembali penggunaan memori; Tapi bisakah Anda membantu menjawab pertanyaan terkait saya? stackoverflow.com/questions/47071265/…
Paradise
Berikut cara mendapatkan jawaban yang benar: stackoverflow.com/a/57315975/1058199
Alex Zavatone

Jawaban:

134

Untuk mendapatkan byte sebenarnya dari memori yang digunakan aplikasi Anda, Anda dapat melakukan sesuatu seperti contoh di bawah ini. Namun, Anda benar-benar harus terbiasa dengan berbagai alat pembuatan profil serta mereka dirancang untuk memberi Anda gambaran penggunaan yang jauh lebih baik secara keseluruhan.

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

Ada juga bidang dalam struktur info.virtual_size yang akan memberi Anda jumlah byte memori virtual yang tersedia (atau memori yang dialokasikan ke aplikasi Anda sebagai memori virtual potensial dalam peristiwa apa pun). Kode yang ditautkan ke pgb akan memberi Anda jumlah memori yang tersedia untuk perangkat dan jenis memorinya.

Jason Coco
sumber
4
terima kasih, persis seperti yang saya cari. Apakah metode app store ini aman?
Buju
3
Jika Anda Cmd + Klik task_basic_info, tampaknya ini sekarang tidak boleh digunakan dan diganti dengan mach_task_basic_info. Dugaan saya adalah bahwa versi ini tidak kompatibel dengan arsitektur 64-bit, tetapi tidak terlalu yakin.
cprcrack
14
Dalam kasus saya, jumlah yang dikembalikan lebih dari dua kali lipat dari laporan memori di XCode. Tidak yakin apa yang membuatnya.
Mork mulai
1
Bagaimana cara mendapatkan penggunaan memori oleh aplikasi lain?
Amit Khandelwal
1
@Morkrom sudahkah Anda tahu mengapa? Saya memiliki masalah yang sama sekitar dua kali lebih besar menjalankan simulator dan hampir 3 kali pada perangkat.
Julian Król
31

Header untuk TASK_BASIC_INFOmengatakan:

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

Ini adalah versi yang menggunakan 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));
    }
}
kombinatorial
sumber
Adakah ide mengapa nilai yang dicatat di sini sekitar dua kali lebih besar pada simulator daripada laporan Xcode dan tiga kali pada perangkat nyata?
Julian Król
1
Saya tidak tahu mengapa ada perbedaan. Itu akan menjadi pertanyaan baru yang bagus.
kombinatorial
1
Saya menemukan perbedaannya. Itu karena memori penduduk bukan byte langsung
Julian Król
Bisakah kita mendapatkan penggunaan memori dari aplikasi lain ?? @combinatorial
Vikas Bansal
1
@VikasBansal tidak, Anda tidak bisa.
kombinatorial
18

Berikut ini report_memory () ditingkatkan untuk menampilkan status kebocoran dengan cepat di 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;
}
Doug Null
sumber
2
ukuran harus TASK_BASIC_INFO_COUNT bukan sizeof (info) - kesalahan ini disalin-tempel ke banyak tempat dengan kode yang sama
Maxim Kholyavkin
18

Ini telah diuji pada Xcode 11 di Mojave 10.4.6 pada 07/01/2019.

Semua jawaban sebelumnya memberikan hasil yang salah .

Berikut adalah cara mendapatkan nilai yang diharapkan yang ditulis oleh Quinn Apple "The Eskimo!".

Ini menggunakan phys_footprintvar from Darwin > Mach > task_infodan sangat cocok dengan nilai dalam pengukur memori di navigator Debug Xcode .

Nilai yang dikembalikan dalam byte.

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

Kode asli mengikuti.

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  
}  

Memodifikasi ini sedikit untuk membuat kumpulan metode Swift tingkat kelas memungkinkan pengembalian byte aktual dan keluaran yang diformat dengan mudah dalam MB untuk ditampilkan. Saya menggunakan ini sebagai bagian dari rangkaian UITest otomatis untuk mencatat memori yang digunakan sebelum dan setelah beberapa iterasi dari tes yang sama untuk melihat apakah kami memiliki potensi kebocoran atau alokasi yang perlu kami perhatikan.

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

Nikmati!

Catatan: pembuat kode yang giat mungkin ingin menambahkan pemformat statis ke kelas sehingga usedMBAsStringhanya mengembalikan 2 tempat desimal yang signifikan.

Alex Zavatone
sumber
7

Solusi cepat dari jawaban Jason Coco :

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))")
    }
}
Nazariy Vlizlo
sumber
apa yang harus dilakukan jika kita ingin tahu berapa banyak ram yang digunakan beberapa aplikasi lain (skype)?
Vikas Bansal
4

Swift 3.1 (Per 8 Agustus 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/(1024*1024)
        print("used megabytes: \(usedMegabytes)")
    } else {
        print("Error with task_info(): " +
            (String(cString: mach_error_string(kerr), encoding: String.Encoding.ascii) ?? "unknown error"))
    }

}
BennyTheNerd
sumber
1
Penggunaan memori yang menggunakan kode ini menunjukkan x3 kali penggunaan memori dari debugger. Mengapa?
1
Saya rasa Anda perlu membaginya (1024*1024), bukan dengan 1000000, untuk mendapatkan megabyte dari byte.
ivanzoid
Itu tidak membuat perbedaan x3.
dekade
ini memberikan nilai memori yang nyata, seperti dalam debugger Xcode, terima kasih
tatiana_c
2

Inilah Versi Swift 3:

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)   
}
jeffbailey.dll
sumber
2
Penggunaan memori yang menggunakan kode ini menunjukkan x3 kali penggunaan memori dari debugger. Mengapa?
bahkan saya memiliki masalah yang sama untuk saya hampir tiga kali lebih tinggi dari apa yang ditampilkan di profil?
Sandy
-1

Versi Objective-C:

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);
}
Jimmy Yin
sumber
-2

Di bawah ini adalah jawaban yang benar:

``

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

``

rensq
sumber
Ini tidak hanya mengembalikan nilai yang salah, memanggil metode memori "Fisika" berarti Anda benar-benar perlu meninjau kode Anda lebih sering.
Alex Zavatone