İPhone'da bellek kullanımını programlı olarak alın


102

İPhone uygulamamın kullandığı bellek miktarını herhangi bir zamanda program aracılığıyla almaya çalışıyorum. Evet, ObjectAlloc / Leaks hakkında bilgi sahibiyim. Bunlarla ilgilenmiyorum, sadece bazı kod yazmanın ve kullanılan bayt miktarını almanın ve NSLog aracılığıyla rapor etmenin mümkün olup olmadığını bilmek.

Teşekkürler.


Dostum, bellek kullanımını zaten başarıyla geri aldım; Ama ilgili sorularıma cevap verebilir misin? stackoverflow.com/questions/47071265/…
Paradise

Doğru cevabı nasıl alacağınız aşağıda açıklanmıştır: stackoverflow.com/a/57315975/1058199
Alex Zavatone

Yanıtlar:


135

Uygulamanızın kullandığı gerçek bellek baytlarını elde etmek için aşağıdaki örnek gibi bir şey yapabilirsiniz. Bununla birlikte, çeşitli profil oluşturma araçlarına gerçekten aşina olmalısınız ve bunların yanı sıra size genel kullanım hakkında çok daha iyi bir resim sunmak için tasarlanmışlardır.

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

Ayrıca info.virtual_size yapısında size kullanılabilir sanal bellek sayısını (veya uygulamanıza herhangi bir durumda potansiyel sanal bellek olarak ayrılan belleği) verecek bir alan vardır. Pgb'nin bağlandığı kod, size cihaz için kullanılabilir bellek miktarını ve ne tür bir bellek olduğunu verecektir.


4
teşekkürler, tam olarak aradığım şey. Bu yöntem uygulama mağazası güvenli midir?
Buju

3
Task_basic_info'ya Cmd + tıklarsanız, bu artık kullanılmamalı ve mach_task_basic_info ile değiştirilmemelidir. Tahminimce bu sürüm 64 bit mimariyle uyumlu değil, ancak pek de emin değil.
cprcrack

14
Benim durumumda, iade edilen miktar XCode'daki bellek raporunun koyduğunun iki katından fazla. Ne yapacağımı bilmiyorum.
Morkrom

1
Diğer uygulamalar tarafından bellek kullanımı nasıl elde edilir?
Amit Khandelwal

1
@Morkrom nedenini anladın mı? Aynı problemi iki kat daha büyük çalışan simülatörde ve bir cihazda neredeyse 3 kez yaşıyorum.
Julian Król

32

Başlıklar TASK_BASIC_INFOşunları söylüyor:

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

İşte kullanan bir sürüm 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));
    }
}

Burada kaydedilen değerin neden bir simülatörde Xcode raporlarından yaklaşık iki kat ve gerçek bir cihazda üç kat daha büyük olduğuna dair bir fikriniz var mı?
Julian Król

1
Neden farkın olduğunu bilmiyorum. Bu yeni ve güzel bir soru olur.
kombinatoryal

1
Farkı buldum. Bunun nedeni yerleşik bellek değil, canlı baytlar değil
Julian Król

diğer uygulamaların bellek kullanımını öğrenebilir miyiz? @combinatorial
Vikas Bansal

1
@VikasBansal hayır yapamazsın.
kombinatoryal

18

NSLog () içindeki sızıntı durumunu hızla göstermek için geliştirilmiş report_memory () burada.

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

2
boyut, sizeof (info) yerine TASK_BASIC_INFO_COUNT olmalıdır - bu hata aynı kodla birçok yere kopyalanıp yapıştırılır
Maxim Kholyavkin

18

Bu, 07/01/2019 tarihinde Mojave 10.4.6'da Xcode 11 üzerinde test edilmiştir.

Önceki yanıtların tümü yanlış sonucu döndürür .

Apple'ın Quinn “The Eskimo!” Tarafından yazılan beklenen değeri nasıl elde edeceğiniz aşağıda açıklanmıştır.

Bu kullanır phys_footprintVAR'ı Darwin > Mach > task_infove yakından Xcode en ayıklama gezginindeki hafıza göstergesi değeri ile eşleşen .

Döndürülen değer bayt cinsindendir.

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

Orijinal kod aşağıdaki gibidir.

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  
}  

Sınıf düzeyinde bir Swift yöntemleri kümesi oluşturmak için bunu biraz değiştirmek, gerçek baytların ve ekran için MB cinsinden biçimlendirilmiş çıktının kolayca geri döndürülmesini sağlar. Bunu, incelememiz gereken herhangi bir potansiyel sızıntı veya tahsis olup olmadığını görmek için aynı testin birden çok yinelemesinden önce ve sonra kullanılan belleği kaydetmek için otomatik bir UITest paketinin parçası olarak kullanıyorum.

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

Zevk almak!

Not: Girişimci bir kodlayıcı, sınıfa statik bir biçimlendirici eklemek isteyebilir, böylece usedMBAsStringyalnızca 2 anlamlı ondalık basamak döndürür.


7

Jason Coco'nun cevabının hızlı çözümü :

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

Başka bir uygulamanın (skype) ne kadar ram kullandığını bilmek istiyorsak ne yapmalıyız?
Vikas Bansal

4

Swift 3.1 (8 Ağustos 2017 itibarıyla)

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

}

1
Bu kodu kullanan bellek kullanımı, hata ayıklayıcıdan gelen bellek kullanımının x3 katını gösterir. Neden?

1
Ben de senin bölme gerekiyor galiba (1024*1024)vermeyerek, 1000000bayt gelen megabayt almak için,.
ivanzoid

Bu x3'ün farkını yaratmaz.
on yıllar

Xcode hata ayıklayıcıda olduğu gibi gerçek bir bellek değeri verir, teşekkürler
tatiana_c

2

İşte bir Swift 3 Sürümü:

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

2
Bu kodu kullanan bellek kullanımı, hata ayıklayıcıdan gelen bellek kullanımının x3 katını gösterir. Neden?

hatta benim için aynı sorunu profilde gösterilenden neredeyse üç kat daha fazla yaşıyorum?
Sandy

-1

Objective-C sürümü:

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

-2

Doğru cevap aşağıdadır:

''

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

''


Bu yalnızca yanlış değeri döndürmekle kalmaz, "Fizik" belleği yöntemini çağırmak, kodunuzu gerçekten daha sık gözden geçirmeniz gerektiği anlamına gelir.
Alex Zavatone
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.