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
고마워요, 정확히 제가 찾던 것입니다. 이 방법 앱 스토어는 안전한가요?
Buju

3
task_basic_info를 Cmd + Click하면 이제 사용하지 말고 mach_task_basic_info로 바꿔야하는 것 같습니다. 내 생각에이 버전은 64 비트 아키텍처와 호환되지 않지만 실제로는 확실하지 않습니다.
cprcrack

14
제 경우에는 반환 된 양이 XCode의 메모리 보고서가 출력하는 것의 두 배 이상입니다. 무엇을 만들어야할지 모르겠습니다.
Morkrom

1
다른 응용 프로그램에서 메모리 사용량을 얻는 방법은 무엇입니까?
Amit Khandelwal

1
@Morkrom이 이유를 알아 냈습니까? 나는 두 배 더 큰 시뮬레이터와 거의 3 배의 장치에서 같은 문제가 있습니다.
Julian Król 2015 년

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 보고서보다 약 2 배, 실제 장치에서 3 배 더 큰 이유를 아십니까?
Julian Król 2015 년

1
왜 그 차이가 있는지 모르겠습니다. 그것은 좋은 새로운 질문이 될 것입니다.
결합

1
차이점을 찾았습니다. 이 때문에 상주 메모리가 아닌 라이브 바이트입니다
줄리안 크롤

다른 응용 프로그램의 메모리 사용량을 얻을 수 있습니까 ?? @combinatorial
카스 반살

1
@VikasBansal 안돼.
combinatorial

18

다음은 NSLog ()에서 누출 상태를 빠르게 표시하도록 개선 된 report_memory ()입니다.

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
size는 sizeof (info) 대신 TASK_BASIC_INFO_COUNT 여야합니다.이 실수는 동일한 코드로 여러 곳에 복사하여 붙여 넣었습니다
Maxim Kholyavkin 2013

18

이것은 2019 년 7 월 1 일 Mojave 10.4.6의 Xcode 11에서 테스트되었습니다.

이전 답변은 모두 잘못된 결과를 반환합니다 .

다음은 Apple의 Quinn "The Eskimo!"가 작성한 예상 값을 얻는 방법입니다.

이것은 phys_footprintvar from을 사용하고 Xcode의 Debug navigator의 메모리 게이지 값Darwin > Mach > task_info거의 일치합니다 .

반환 된 값은 바이트 단위입니다.

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

다른 응용 프로그램 (스카이프)이 얼마나 많은 램을 사용하고 있는지 알고 싶다면 어떻게해야합니까?
Vikas Bansal 2015 년

4

Swift 3.1 (2017 년 8 월 8 일 기준)

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 디버거에서와 같이 실제 메모리 값을 제공합니다. 감사합니다.
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

-1

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

다음은 정답입니다.

```

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

```


이것은 잘못된 값을 반환 할뿐만 아니라 "Physics"메모리 메서드를 호출하면 실제로 코드를 더 자주 검토해야 함을 의미합니다.
Alex Zavatone
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.