web-dev-qa-db-ja.com

iOSアプリの最大メモリバジェット

最低限3gsをターゲットとするiOSゲームに取り組んでいます。 Retinaディスプレイデバイス(iphone 4、iPod touch第4世代)にHDアセットを使用しています。

メモリに関しては、iPod Touch第4世代は3gsと同じ量のRAM(Iphone 4の512と比較して256)を持っていますが、HDアセットを使用しているため、私たちにとって最も制約の多いデバイスのようです。 100-110mbのRAMをロードしようとしたときにアプリがクラッシュしていましたが、70MBになったので、ロードクラッシュはありませんでした。

何度も検索した後、公式のハード制限はないようですので、安全に使用するメモリ予算を知るにはどうすればよいですか?各マップのメモリを心配することなく、アーティストが使用できる予算を提供できるようにしたいと考えています。

142
frilla

あなたはあなた自身の質問に答えたと思います:70 Mbの制限を超えないようにしてください、しかしそれは本当に多くのことに依存しています:使用しているiOSバージョン(SDKではない)、バックグラウンドで実行されているアプリケーションの数、正確なメモリあなたが使用しているなど。

インスタントメモリのスプラッシュを回避します(たとえば、40 MBのRAMを使用し、短い計算のために80 MB以上を割り当てます)。この場合、iOSはアプリケーションをすぐに強制終了します。

また、アセットの遅延読み込みを検討する必要があります(事前にではなく、本当に必要な場合にのみ読み込みます)。

38
Max

Splitユーティリティを使用したテストの結果は次のように書かれています(リンクは彼の答えにあります)。

デバイス:(クラッシュ量/合計量/合計の割合)

  • iPad1:127MB/256MB/49%
  • iPad2:275MB/512MB/53%
  • iPad3:645MB/1024MB/62%
  • iPad4:585MB/1024MB/57%(iOS 8.1)
  • iPad Mini第1世代:297MB/512MB/58%
  • iPad Mini Retina:696MB/1024MB/68%(iOS 7.1)
  • iPad Air:697MB/1024MB/68%
  • iPad Air 2:1383MB/2048MB/68%(iOS 10.2.1)
  • iPad Pro 9.7 ":1395MB/1971MB/71%(iOS 10.0.2(14A456))
  • iPad Pro 10.5”:3057/4000/76%(iOS 11 beta4)
  • iPad Pro 12.9”(2015):3058/3999/76%(iOS 11.2.1)
  • iPad Pro 12.9”(2017):3057/3974/77%(iOS 11 beta4)
  • iPad Pro 11.0”(2018):2858/3769/76%(iOS 12.1)
  • iPad Pro 12.9”(2018、1TB):4598/5650/81%(iOS 12.1)
  • iPod touch第4世代:130MB/256MB/51%(iOS 6.1.1)
  • iPod touch第5世代:286MB/512MB/56%(iOS 7.0)
  • iPhone4:325MB/512MB/63%
  • iPhone4s:286MB/512MB/56%
  • iPhone5:645MB/1024MB/62%
  • iPhone5s:646MB/1024MB/63%
  • iPhone6:645MB/1024MB/62%(iOS 8.x)
  • iPhone6 +:645MB/1024MB/62%(iOS 8.x)
  • iPhone6s:1396MB/2048MB/68%(iOS 9.2)
  • iPhone6s +:1392MB/2048MB/68%(iOS 10.2.1)
  • iPhoneSE:1395MB/2048MB/69%(iOS 9.3)
  • iPhone7:1395/2048MB/68%(iOS 10.2)
  • iPhone7 +:2040MB/3072MB/66%(iOS 10.2.1)
  • iPhone8:1364/1990MB/70%(iOS 12.1)
  • iPhone X:1392/2785/50%(iOS 11.2.1)
  • iPhone XS:2040/3754/54%(iOS 12.1)
  • iPhone XS Max:2039/3735/55%(iOS 12.1)
  • iPhone XR:1792/2813/63%(iOS 12.1)
391
Jasper

できるだけ多くのメモリをクラッシュに割り当て、メモリの警告とクラッシュが発生したときに記録する小さなユーティリティを作成しました。これは、iOSデバイスのメモリバジェットを調べるのに役立ちます。

https://github.com/Split82/iOSMemoryBudgetTest

130
Split

私のアプリでは、より多くのメモリを使用するとユーザーエクスペリエンスが向上するため、didReceiveMemoryWarningで使用できるメモリを本当にall解放する必要があるかどうかを判断する必要があります。 Splitと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
}
17
cprcrack

SPLITSリポジトリをフォークすることで、Today's Extensionに割り当てることができるiOSメモリをテストするためにビルドしました

iOSMemoryBudgetTestForExtension

以下はiPhone 5sで得た結果です

10 MBでのメモリ警告

アプリが12 MBでクラッシュした

これは、Appleが、拡張機能がその潜在能力を最大限に発揮できるようにすることを意味しているだけです

8
Harsh

WWDC 2010 Session videos のセッション147を見る必要があります。 「iPhone OSの高度なパフォーマンス最適化、パート2」です。
メモリの最適化に関する多くの良いアドバイスがあります。

ヒントの一部は次のとおりです。

  • ネストされたNSAutoReleasePoolsを使用して、メモリ使用量が急増しないようにします。
  • 大きな画像からサムネイルを作成する場合は、CGImageSourceを使用します。
  • メモリ不足の警告に対応します。
7
Kobski
- (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)

JaspersリストをデバイスRAMでソートして、もう1つのリストを作成しました(Splitのツールで独自のテストを行い、いくつかの結果を修正しました-Jaspersスレッドでコメントを確認してください)。

デバイスRAM:クラッシュする範囲

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

特殊なケース:

  • iPhone X(3072MB):50%
  • iPhone XS/XS Max(4096MB):55%
  • iPhone XR(3072MB):テストされていません(コメントのクラッシュ値を投稿してください)

デバイスRAMは簡単に読み取ることができます。

[NSProcessInfo processInfo].physicalMemory

私の経験から、1GBデバイスでは45%、2/3GBデバイスでは50%、4GBデバイスでは55%を使用しても安全です。 macOSの割合は少し大きくなる場合があります。

2
Slyv