เรียกข้อมูลการใช้หน่วยความจำบน iPhone โดยใช้โปรแกรม


101

ฉันกำลังพยายามดึงข้อมูลจำนวนหน่วยความจำที่แอพ iPhone ของฉันใช้อยู่ตลอดเวลาโดยใช้โปรแกรม ใช่ฉันทราบเกี่ยวกับ ObjectAlloc / Leaks ฉันไม่สนใจสิ่งเหล่านี้เพียง แต่รู้ว่าเป็นไปได้ไหมที่จะเขียนโค้ดและรับจำนวนไบต์ที่ใช้และรายงานผ่าน NSLog

ขอบคุณ.


ฉันเรียกข้อมูลการใช้หน่วยความจำสำเร็จแล้ว แต่คุณช่วยตอบคำถามที่เกี่ยวข้องของฉันได้ไหม stackoverflow.com/questions/47071265/…
Paradise

วิธีหาคำตอบที่ถูกต้อง: stackoverflow.com/a/57315975/1058199
Alex Zavatone

คำตอบ:


134

หากต้องการรับไบต์จริงของหน่วยความจำที่แอปพลิเคชันของคุณใช้คุณสามารถทำสิ่งต่างๆดังตัวอย่างด้านล่าง อย่างไรก็ตามคุณควรทำความคุ้นเคยกับเครื่องมือทำโปรไฟล์ต่างๆอย่างแท้จริงรวมทั้งได้รับการออกแบบมาเพื่อให้คุณได้ภาพรวมการใช้งานที่ดีขึ้นมาก

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

นอกจากนี้ยังมีฟิลด์ในโครงสร้าง info.virtual_size ซึ่งจะให้จำนวนไบต์หน่วยความจำเสมือนที่มีอยู่ (หรือหน่วยความจำที่จัดสรรให้กับแอปพลิเคชันของคุณเป็นหน่วยความจำเสมือนที่มีศักยภาพในทุกเหตุการณ์) รหัสที่ pgb เชื่อมโยงไปจะให้จำนวนหน่วยความจำที่มีอยู่ในอุปกรณ์และหน่วยความจำประเภทใด


4
ขอบคุณสิ่งที่ฉันกำลังค้นหา App Store วิธีนี้ปลอดภัยหรือไม่?
Buju

3
หากคุณ Cmd + คลิก task_basic_info ดูเหมือนว่าตอนนี้ไม่ควรใช้และแทนที่ด้วย mach_task_basic_info ฉันเดาว่าเวอร์ชันนี้ไม่รองรับสถาปัตยกรรม 64 บิต แต่ไม่แน่ใจจริงๆ
cprcrack

14
ในกรณีของฉันจำนวนที่ส่งคืนมากกว่าสองเท่าของรายงานหน่วยความจำใน XCode ไม่แน่ใจว่าจะทำจากอะไร
Morkrom

1
จะรับการใช้งานหน่วยความจำโดยแอปพลิเคชันอื่นได้อย่างไร?
Amit Khandelwal

1
@Morkrom คุณคิดว่าทำไม? ฉันมีปัญหาเดียวกันกับเครื่องจำลองการวิ่งที่ใหญ่กว่าสองเท่าและเกือบ 3 เท่าบนอุปกรณ์
Julian Król

31

ส่วนหัวสำหรับTASK_BASIC_INFOพูดว่า:

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

นี่คือเวอร์ชันที่ใช้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));
    }
}

มีความคิดว่าทำไมค่าที่บันทึกที่นี่จึงใหญ่กว่ารายงาน Xcode ประมาณสองเท่าและสามเท่าบนอุปกรณ์จริง
Julian Król

1
ฉันไม่รู้ว่าทำไมความแตกต่าง นั่นจะทำให้เกิดคำถามใหม่ที่ดี
combinatorial

1
ฉันพบความแตกต่าง เป็นเพราะหน่วยความจำของผู้อยู่อาศัยไม่ใช่ไบต์สด
Julian Król

เราจะใช้หน่วยความจำของแอปพลิเคชันอื่นได้ไหม @combinatorial
Vikas Bansal

1
@VikasBansal ไม่คุณทำไม่ได้
combinatorial

18

ต่อไปนี้คือ report_memory () ที่ปรับปรุงเพื่อแสดงสถานะการรั่วไหลอย่างรวดเร็วใน 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;
}

2
ขนาดควรเป็น TASK_BASIC_INFO_COUNT แทนที่จะเป็น sizeof (ข้อมูล) - ข้อผิดพลาดนี้คัดลอกไปยังหลายที่ที่มีรหัสเดียวกัน
Maxim Kholyavkin

18

สิ่งนี้ได้รับการทดสอบบน Xcode 11 ใน Mojave 10.4.6 เมื่อ 07/01/2019

ทุกคำตอบก่อนหน้านี้กลับผลลัพธ์ไม่ถูกต้อง

นี่คือวิธีรับค่าที่คาดหวังซึ่งเขียนโดย Quinn“ The Eskimo!” ของ Apple

นี้ใช้phys_footprintvar จากDarwin > Mach > task_infoและใกล้เคียงกับค่าในวัดหน่วยความจำใน Xcode ของ Debug นำทาง

ค่าที่ส่งคืนเป็นไบต์

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

รหัสเดิมมีดังนี้

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  
}  

การแก้ไขเล็กน้อยเพื่อสร้างชุดระดับคลาสของวิธีการ Swift ช่วยให้สามารถคืนค่าไบต์จริงและเอาต์พุตที่จัดรูปแบบเป็น MB สำหรับการแสดงผลได้อย่างง่ายดาย ฉันใช้สิ่งนี้เป็นส่วนหนึ่งของชุด UITest อัตโนมัติเพื่อบันทึกหน่วยความจำที่ใช้ก่อนและหลังการทดสอบเดียวกันซ้ำหลายครั้งเพื่อดูว่าเรามีการรั่วไหลหรือการจัดสรรที่เราต้องตรวจสอบหรือไม่

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

สนุก!

หมายเหตุ: ผู้เขียนโค้ดกล้าได้กล้าเสียอาจต้องการเพิ่มตัวจัดรูปแบบคงที่ให้กับคลาสเพื่อให้usedMBAsStringส่งกลับทศนิยมที่มีนัยสำคัญเพียง 2 ตำแหน่งเท่านั้น


7

คำตอบของ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))")
    }
}

จะทำอย่างไรถ้าอยากรู้ว่าแอพพลิเคชั่นอื่น ๆ (skype) ใช้ ram มากแค่ไหน?
Vikas Bansal

4

Swift 3.1 (ณ วันที่ 8 สิงหาคม 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"))
    }

}

1
การใช้หน่วยความจำโดยใช้รหัสนี้แสดง x3 เท่าของการใช้หน่วยความจำจากดีบักเกอร์ ทำไม?

1
ผมเดาว่าคุณต้องหารด้วย(1024*1024)ไม่ใช่ด้วย1000000เพื่อให้ได้เมกะไบต์จากไบต์
ivanzoid

นั่นไม่ได้สร้างความแตกต่างของ x3
ทศวรรษ

มันให้ค่าหน่วยความจำจริงเช่นเดียวกับใน Xcode debugger ขอบคุณ
tatiana_c

2

นี่คือเวอร์ชัน 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)   
}

2
การใช้หน่วยความจำโดยใช้รหัสนี้แสดง x3 เท่าของการใช้หน่วยความจำจากดีบักเกอร์ ทำไม?

แม้ว่าฉันจะมีปัญหาเดียวกันสำหรับฉันสูงกว่าเกือบสามเท่าที่แสดงในโปรไฟล์?
Sandy


-2

ด้านล่างนี้คือคำตอบที่ถูกต้อง:

``

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

``


สิ่งนี้ไม่เพียงส่งคืนค่าที่ไม่ถูกต้องเท่านั้นการเรียกหน่วยความจำเมธอด "ฟิสิกส์" หมายความว่าคุณต้องตรวจสอบโค้ดของคุณบ่อยขึ้น
Alex Zavatone
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.