Truy xuất theo chương trình sử dụng bộ nhớ trên iPhone


101

Tôi đang cố gắng truy xuất dung lượng bộ nhớ mà ứng dụng iPhone của tôi đang sử dụng bất cứ lúc nào, theo chương trình. Có, tôi biết về ObjectAlloc / Rò rỉ. Tôi không quan tâm đến những điều đó, chỉ để biết liệu có thể viết một số mã và lấy số lượng byte đang được sử dụng và báo cáo nó qua NSLog.

Cảm ơn.


Trời ạ, tôi đã truy xuất mức sử dụng bộ nhớ thành công rồi; Nhưng bạn có thể giúp trả lời các câu hỏi liên quan của tôi không? stackoverflow.com/questions/47071265/…
Paradise

Đây là cách để có câu trả lời chính xác: stackoverflow.com/a/57315975/1058199
Alex Zavatone

Câu trả lời:


134

Để lấy số byte bộ nhớ thực tế mà ứng dụng của bạn đang sử dụng, bạn có thể làm như ví dụ bên dưới. Tuy nhiên, bạn thực sự nên làm quen với các công cụ lập hồ sơ khác nhau cũng như chúng được thiết kế để cung cấp cho bạn bức tranh toàn cảnh hơn về việc sử dụng.

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

Cũng có một trường trong cấu trúc info.virtual_size sẽ cung cấp cho bạn số byte bộ nhớ ảo có sẵn (hoặc bộ nhớ được cấp cho ứng dụng của bạn dưới dạng bộ nhớ ảo tiềm năng trong bất kỳ trường hợp nào). Mã mà pgb liên kết tới sẽ cung cấp cho bạn dung lượng bộ nhớ có sẵn trên thiết bị và loại bộ nhớ đó là.


4
cảm ơn, chính xác những gì tôi đang tìm kiếm. Kho ứng dụng phương pháp này có an toàn không?
Buju

3
Nếu bạn Cmd + Nhấp vào task_basic_info, có vẻ như điều này bây giờ không nên được sử dụng và thay thế bằng mach_task_basic_info. Tôi đoán là phiên bản này không tương thích với kiến ​​trúc 64-bit, nhưng không thực sự chắc chắn.
cprcrack.

14
Trong trường hợp của tôi, số tiền trả về nhiều gấp đôi so với báo cáo bộ nhớ trong XCode đưa ra. Không chắc chắn những gì để làm cho nó.
Morkrom

1
Làm thế nào để sử dụng bộ nhớ của các ứng dụng khác?
Amit Khandelwal,

1
@Morkrom bạn đã hiểu tại sao chưa? Tôi gặp vấn đề tương tự khi chạy bộ mô phỏng lớn hơn gấp đôi và gần gấp 3 lần trên một thiết bị.
Julian Król

31

Các tiêu đề cho TASK_BASIC_INFOnói:

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

Đây là phiên bản sử dụng 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));
    }
}

Bất kỳ ý tưởng nào tại sao giá trị được ghi ở đây lớn hơn khoảng hai lần trên trình mô phỏng so với báo cáo Xcode và ba lần trên thiết bị thực?
Julian Król

1
Tôi không biết tại sao sự khác biệt. Đó sẽ là một câu hỏi mới hay.
tổ hợp

1
Tôi đã tìm thấy sự khác biệt. Đó là vì bộ nhớ thường trú không phải là các byte trực tiếp
Julian Krol

chúng ta có thể sử dụng bộ nhớ của các ứng dụng khác không ?? @combinatorial
Vikas Bansal

1
@VikasBansal không bạn không thể.
tổ hợp

18

Đây là report_memory () được nâng cao để hiển thị nhanh tình trạng rò rỉ trong 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
kích thước phải là TASK_BASIC_INFO_COUNT thay vì sizeof (thông tin) - lỗi này được sao chép dán vào nhiều nơi có cùng mã
Maxim Kholyavkin

18

Điều này đã được thử nghiệm trên Xcode 11 trong Mojave 10.4.6 vào ngày 07/01/2019.

Tất cả các câu trả lời trước đó đều trả về kết quả không chính xác .

Đây là cách nhận được giá trị mong đợi được viết bởi Quinn của Apple “The Eskimo!”.

Điều này sử dụng phys_footprintvar from Darwin > Mach > task_infokhớp chặt chẽ với giá trị trong bộ nhớ trong trình điều hướng Gỡ lỗi của Xcode .

Giá trị trả về tính bằng byte.

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

Mã gốc sau đây.

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ửa đổi một chút điều này để tạo một tập hợp các phương thức Swift ở cấp độ lớp cho phép dễ dàng trả về các byte thực tế và đầu ra được định dạng theo MB để hiển thị. Tôi sử dụng phần mềm này như một phần của bộ UITest tự động để ghi lại bộ nhớ được sử dụng trước và sau nhiều lần lặp lại của cùng một thử nghiệm để xem liệu chúng tôi có bất kỳ rò rỉ hoặc phân bổ tiềm năng nào mà chúng tôi cần xem xét hay không.

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

Thưởng thức!

Lưu ý: một lập trình viên táo bạo có thể muốn thêm một trình định dạng tĩnh vào lớp để usedMBAsStringchỉ trả về 2 chữ số thập phân quan trọng.


7

Giải pháp nhanh chóng cho câu trả lời của 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))")
    }
}

phải làm gì nếu chúng ta muốn biết một số ứng dụng (skype) khác đang sử dụng bao nhiêu ram?
Vikas Bansal

4

Swift 3.1 (Kể từ ngày 8 tháng 8 năm 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
Việc sử dụng bộ nhớ bằng mã này hiển thị x3 lần mức sử dụng bộ nhớ từ trình gỡ lỗi. Tại sao?

1
Vâng, tôi đoán bạn cần phải chia cho (1024*1024), không phải cho 1000000, để có được megabyte từ byte.
ivanzoid

Điều đó không tạo nên sự khác biệt của x3.
thập kỷ

nó cung cấp một giá trị bộ nhớ thực, như trong trình gỡ lỗi Xcode, cảm ơn
tatiana_c

2

Đây là phiên bản 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
Việc sử dụng bộ nhớ bằng mã này hiển thị x3 lần mức sử dụng bộ nhớ từ trình gỡ lỗi. Tại sao?

thậm chí tôi có cùng một vấn đề đối với tôi cao hơn gần ba lần những gì đang hiển thị trong hồ sơ?
Sandy

-1

Phiên bản 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);
}

-2

Dưới đây là câu trả lời chính xác:

``

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

``


Điều này không chỉ trả về giá trị không chính xác, việc gọi phương thức là bộ nhớ "Vật lý" có nghĩa là bạn thực sự cần phải xem lại mã của mình thường xuyên hơn.
Alex Zavatone
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.