programing

ios app 최대 메모리 예산

powerit 2023. 6. 2. 21:22
반응형

ios app 최대 메모리 예산

저는 최소 3gs를 목표로 하는 iOS 게임을 만들고 있습니다.우리는 레티나 디스플레이 장치(아이폰 4, 아이팟 터치 4세대)에 HD 자산을 사용하고 있습니다.

기억하기로는, 아이팟 터치 4세대는 3gs와 같은 양의 RAM(아이폰 4의 512와 비교해 256개)을 가지고 있지만 HD 자산을 사용하고 있기 때문에 우리에게 가장 제약이 되는 장치인 것 같습니다.예전에는 100~110MB의 램을 로드하려고 할 때 앱이 작동하지 않았는데, 70MB로 줄었으니 로드가 작동하지 않습니다.

많은 검색을 해본 결과 공식적인 하드 리미트는 없는 것 같습니다. 그렇다면 안전을 위해 어떤 메모리 예산을 사용해야 하는지 어떻게 알 수 있을까요?우리는 아티스트들에게 각각의 지도에 대한 기억 걱정 없이 사용할 수 있는 예산을 제공할 수 있기를 원합니다.

스플릿이 작성한 유틸리티를 사용한 테스트 결과(링크는 그의 답변에 있음):

장치: (총량/총량/총량 백분율)

  • 아이패드1: 127MB/256MB/49%
  • 아이패드2: 275MB/512MB/53%
  • 아이패드3: 645MB/1024MB/62%
  • 아이패드4: 585MB/1024MB/57%(iOS 8.1)
  • 아이패드 미니 1세대: 297MB/512MB/58%
  • iPad Mini retina: 696MB/1024MB/68%(iOS 7.1)
  • 아이패드 에어: 697MB/1024MB/68%
  • 아이패드 에어 2: 1383MB/2048MB/68%(iOS 10.2.1)
  • iPad Pro 9.7": 1395MB/1971MB/71%(iOS 10.0.2(14A456))
  • 아이패드 프로 10.5": 3057/4000/76%(iOS 11 베타4)
  • 아이패드 프로 12.9인치(2015): 3058/3999/76%(iOS 11.2.1)
  • 아이패드 프로 12.9" (2017): 3057/3974/77% (iOS 11 베타4)
  • 아이패드 프로 11.0" (2018): 2858/3769/76% (iOS 12.1)
  • iPad Pro 12.9인치(2018, 1TB): 4598/5650/81%(iOS 12.1)
  • 아이패드 10.2: 1844/2998/62% (iOS 13.2.3)
  • iPod touch 4세대: 130MB/256MB/51%(iOS 6.1.1)
  • iPod touch 5세대: 286MB/512MB/56%(iOS 7.0)
  • 아이폰4: 325MB/512MB/63%
  • 아이폰4s: 286MB/512MB/56%
  • 아이폰5: 645MB/1024MB/62%
  • 아이폰5s: 646MB/1024MB/63%
  • 아이폰6: 645MB/1024MB/62%(iOS 8.x)
  • 아이폰6+: 645MB/1024MB/62%(iOS 8.x)
  • 아이폰6s: 1396MB/2048MB/68%(iOS 9.2)
  • 아이폰6s+: 1392MB/2048MB/68%(iOS 10.2.1)
  • 아이폰SE: 1395MB/2048MB/69%(iOS 9.3)
  • 아이폰7: 1395/2048MB/68%(iOS 10.2)
  • 아이폰7+: 2040MB/3072MB/66%(iOS 10.2.1)
  • 아이폰8: 1364/1990MB/70%(iOS 12.1)
  • 아이폰X: 1392/2785/50% (iOS 11.2.1)
  • 아이폰XS: 2040/3754/54% (iOS 12.1)
  • 아이폰XS Max: 2039/3735/55% (iOS 12.1)
  • 아이폰XR: 1792/2813/63% (iOS 12.1)
  • 아이폰 11: 2068/3844/54% (iOS 13.1.3)
  • 아이폰11 프로 맥스: 2067/3740/55% (iOS 13.2.3)
  • 아이폰12 프로: 3054/5703/54% (iOS 16.1)

저는 크래시를 위해 가능한 한 많은 메모리를 할당하고 메모리 경고와 크래시가 발생한 시간을 기록하는 작은 유틸리티를 만들었습니다.이를 통해 iOS 기기의 메모리 예산을 파악할 수 있습니다.

https://github.com/Split82/iOSMemoryBudgetTest

70Mb 제한을 넘지 않도록 노력해야 하지만 실제로 사용하는 iOS 버전(SDK가 아닌), 백그라운드에서 실행 중인 애플리케이션 수, 정확한 메모리 등 여러 가지에 따라 다릅니다.

메모리가 즉시 튀지 않도록 합니다(예: 40Mb의 RAM을 사용한 다음 짧은 계산을 위해 80Mb의 RAM을 더 할당하는 경우).이 경우 iOS는 당신의 애플리케이션을 즉시 삭제할 수 있습니다.

또한 자산의 로드를 늦추는 것도 고려해야 합니다(사전에 로드하지 않고 실제로 필요할 때만 로드).

내 앱에서는 더 많은 메모리를 사용하면 사용자 환경이 더 좋기 때문에 내가 할 수 있는 모든 메모리를 해제해야 하는지 결정해야 합니다.didReceiveMemoryWarning스플릿과 Jasper Pol의 답변에 따르면, 총 장치 메모리의 최대 45%를 사용하는 것은 안전한 임계값인 것 같습니다(감사합니다).

누군가가 실제 구현을 보고 싶어하는 경우:

#import "mach/mach.h"

- (void)didReceiveMemoryWarning
{
    // Remember to call super
    [super didReceiveMemoryWarning];

    // If we are using more than 45% of the memory, free even important resources,
    // because the app might be killed by the OS if we don't
    if ([self __getMemoryUsedPer1] > 0.45)
    {
        // Free important resources here
    }

    // Free regular unimportant resources always here
}

- (float)__getMemoryUsedPer1
{
    struct mach_task_basic_info info;
    mach_msg_type_number_t size = sizeof(info);
    kern_return_t kerr = task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &size);
    if (kerr == KERN_SUCCESS)
    {
        float used_bytes = info.resident_size;
        float total_bytes = [NSProcessInfo processInfo].physicalMemory;
        //NSLog(@"Used: %f MB out of %f MB (%f%%)", used_bytes / 1024.0f / 1024.0f, total_bytes / 1024.0f / 1024.0f, used_bytes * 100.0f / total_bytes);
        return used_bytes / total_bytes;
    }
    return 1;
}

Swift( 답변 기준):

func __getMemoryUsedPer1() -> Float
{
    let MACH_TASK_BASIC_INFO_COUNT = (sizeof(mach_task_basic_info_data_t) / sizeof(natural_t))
    let name = mach_task_self_
    let flavor = task_flavor_t(MACH_TASK_BASIC_INFO)
    var size = mach_msg_type_number_t(MACH_TASK_BASIC_INFO_COUNT)
    var infoPointer = UnsafeMutablePointer<mach_task_basic_info>.alloc(1)
    let kerr = task_info(name, flavor, UnsafeMutablePointer(infoPointer), &size)
    let info = infoPointer.move()
    infoPointer.dealloc(1)
    if kerr == KERN_SUCCESS
    {
        var used_bytes: Float = Float(info.resident_size)
        var total_bytes: Float = Float(NSProcessInfo.processInfo().physicalMemory)
        println("Used: \(used_bytes / 1024.0 / 1024.0) MB out of \(total_bytes / 1024.0 / 1024.0) MB (\(used_bytes * 100.0 / total_bytes)%%)")
        return used_bytes / total_bytes
    }
    return 1
}

SPLITS repo를 포크하여 오늘의 확장에 할당할 수 있는 iOS 메모리를 테스트하기 위해 만들었습니다.

iOS 메모리 예산확장 테스트

다음은 제가 아이폰5s에서 받은 결과입니다.

10MB의 메모리 경고

앱이 12MB에서 손상

이를 통해 Apple은 모든 확장 기능이 최대한의 잠재력을 발휘하도록 허용할 뿐입니다.

당신은 WWDC 2010 세션 비디오에서 147 세션을 시청해야 합니다.그것은 "아이폰 OS의 고급 성능 최적화, 파트 2"입니다.
메모리 최적화에 대한 많은 좋은 조언이 있습니다.

몇 가지 팁은 다음과 같습니다.

  • 내포된 를 합니다.NSAutoReleasePool메모리 사용량이 급증하지 않도록 합니다.
  • 사용하다CGImageSource큰 이미지에서 미리 보기를 만들 때 사용합니다.
  • 메모리 부족 경고에 대응합니다.

iOS13부터는 Apple에서 지원하는 쿼리 방법이 있습니다.

#include <os/proc.h>

size_t os_proc_available_memory(void)

소개: https://developer.apple.com/videos/play/wwdc2019/606/

약 29분 정도입니다.

편집: 문서 https://developer.apple.com/documentation/os/3191911-os_proc_available_memory?language=objc 에 링크 추가

저는 Jaspers 목록을 장치 RAM별로 정렬하여 하나 더 만들었습니다(Split의 툴로 직접 테스트를 했고 몇 가지 결과를 수정했습니다 - Jaspers 스레드에서 제 의견을 확인합니다).

장치 RAM: 충돌 범위(%)

  • 256MB: 49% - 51%
  • 512MB: 53% - 63%
  • 1024MB: 57% - 68%
  • 2048MB: 68% - 69%
  • 3072MB: 63% - 66%
  • 4096MB: 77%
  • 6144MB: 81%

특수한 경우:

  • 아이폰X(3072MB): 50%
  • 아이폰XS/XS Max(4096MB): 55%
  • 아이폰XR(3072MB): 63%
  • 아이폰 11/11 Pro Max (4096MB): 54% - 55%

장치 RAM은 쉽게 읽을 수 있습니다.

[NSProcessInfo processInfo].physicalMemory

제 경험으로는 1GB 기기의 경우 45%, 2/3GB 기기의 경우 50%, 4GB 기기의 경우 55%를 사용하는 것이 안전합니다.macOS의 백분율은 조금 더 클 수 있습니다.

- (float)__getMemoryUsedPer1
{
    struct mach_task_basic_info info;
    mach_msg_type_number_t size = MACH_TASK_BASIC_INFO;
    kern_return_t kerr = task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &size);
    if (kerr == KERN_SUCCESS)
    {
        float used_bytes = info.resident_size;
        float total_bytes = [NSProcessInfo processInfo].physicalMemory;
        //NSLog(@"Used: %f MB out of %f MB (%f%%)", used_bytes / 1024.0f / 1024.0f, total_bytes / 1024.0f / 1024.0f, used_bytes * 100.0f / total_bytes);
        return used_bytes / total_bytes;
    }
    return 1;
}

MACH_TASK_BASIC_INFO 대신 TASK_BASIC_INFO_COUNT를 사용할 경우 다음과 같이 됩니다.

kerr == KERN_INVALID_ARGUMENT (4)

위의 많은 답변과 함께, 저는 Apples의 새로운 방법을 구현했습니다.os_proc_available_memory()iOS 13+와 연결된 경우NSByteCountFormatter메모리의 출력을 향상시키기 위해 다음과 같은 여러 가지 유용한 포맷 옵션을 제공합니다.

#include <os/proc.h>

....

- (NSString *)memoryStringForBytes:(unsigned long long)memoryBytes {
    NSByteCountFormatter *byteFormatter = [[NSByteCountFormatter alloc] init];
    byteFormatter.allowedUnits = NSByteCountFormatterUseGB;
    byteFormatter.countStyle = NSByteCountFormatterCountStyleMemory;
    NSString *memoryString = [byteFormatter stringFromByteCount:memoryBytes];
    return memoryString;
}

- (void)memoryLoggingOutput {
    if (@available(iOS 13.0, *)) {
        NSLog(@"Physical memory available: %@", [self memoryStringForBytes:[NSProcessInfo processInfo].physicalMemory]);
        NSLog(@"Memory A (brackets): %@", [self memoryStringForBytes:(long)os_proc_available_memory()]);
        NSLog(@"Memory B (no brackets): %@", [self memoryStringForBytes:(long)os_proc_available_memory]);
    }
}

중요한 참고:마지막에 있는 것을 잊지 마세요.두 가지를 모두 포함했습니다.NSLog의 옵션memoryLoggingOutput메서드는 괄호가 누락되었음을 경고하지 않으며 괄호를 포함하지 않으면 예기치 않지만 일정한 결과가 반환되기 때문입니다.

메서드에서 반환된 문자열memoryStringForBytes다음과 같은 값을 출력합니다.

NSLog(@"%@", [self memoryStringForBytes:(long)os_proc_available_memory()]); // 1.93 GB
// 2 seconds later
NSLog(@"%@", [self memoryStringForBytes:(long)os_proc_available_memory()]); // 1.84 GB

메모리 사용률(%)뿐만 아니라 메모리 조각화도 중요합니다.애플리케이션이 더 작은 청크와 혼합된 큰 청크를 할당 및 할당 해제하면, 해당 큰 청크는 애플리케이션용 예약 메모리에 들어가지 않고 메모리를 많이 사용한 경우(예: 총 용량의 35%)에도 "젯샘"됩니다.

그런 경우에는 메모리 풀을 사용하고 개체를 다시 사용하는 것을 고려해야 합니다.또한 String-Operations를 많이 사용하면 메모리 음식 인쇄에 좋지 않을 수 있습니다.

언급URL : https://stackoverflow.com/questions/5887248/ios-app-maximum-memory-budget

반응형