最低限3gsをターゲットとするiOSゲームに取り組んでいます。 Retinaディスプレイデバイス(iphone 4、iPod touch第4世代)にHDアセットを使用しています。
メモリに関しては、iPod Touch第4世代は3gsと同じ量のRAM(Iphone 4の512と比較して256)を持っていますが、HDアセットを使用しているため、私たちにとって最も制約の多いデバイスのようです。 100-110mbのRAMをロードしようとしたときにアプリがクラッシュしていましたが、70MBになったので、ロードクラッシュはありませんでした。
何度も検索した後、公式のハード制限はないようですので、安全に使用するメモリ予算を知るにはどうすればよいですか?各マップのメモリを心配することなく、アーティストが使用できる予算を提供できるようにしたいと考えています。
あなたはあなた自身の質問に答えたと思います:70 Mbの制限を超えないようにしてください、しかしそれは本当に多くのことに依存しています:使用しているiOSバージョン(SDKではない)、バックグラウンドで実行されているアプリケーションの数、正確なメモリあなたが使用しているなど。
インスタントメモリのスプラッシュを回避します(たとえば、40 MBのRAMを使用し、短い計算のために80 MB以上を割り当てます)。この場合、iOSはアプリケーションをすぐに強制終了します。
また、アセットの遅延読み込みを検討する必要があります(事前にではなく、本当に必要な場合にのみ読み込みます)。
Splitユーティリティを使用したテストの結果は次のように書かれています(リンクは彼の答えにあります)。
デバイス:(クラッシュ量/合計量/合計の割合)
できるだけ多くのメモリをクラッシュに割り当て、メモリの警告とクラッシュが発生したときに記録する小さなユーティリティを作成しました。これは、iOSデバイスのメモリバジェットを調べるのに役立ちます。
私のアプリでは、より多くのメモリを使用するとユーザーエクスペリエンスが向上するため、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
}
SPLITSリポジトリをフォークすることで、Today's Extensionに割り当てることができるiOSメモリをテストするためにビルドしました
iOSMemoryBudgetTestForExtension
以下はiPhone 5sで得た結果です
10 MBでのメモリ警告
アプリが12 MBでクラッシュした
これは、Appleが、拡張機能がその潜在能力を最大限に発揮できるようにすることを意味しているだけです。
WWDC 2010 Session videos のセッション147を見る必要があります。 「iPhone OSの高度なパフォーマンス最適化、パート2」です。
メモリの最適化に関する多くの良いアドバイスがあります。
ヒントの一部は次のとおりです。
NSAutoReleasePool
sを使用して、メモリ使用量が急増しないようにします。CGImageSource
を使用します。- (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:クラッシュする範囲
特殊なケース:
デバイスRAMは簡単に読み取ることができます。
[NSProcessInfo processInfo].physicalMemory
私の経験から、1GBデバイスでは45%、2/3GBデバイスでは50%、4GBデバイスでは55%を使用しても安全です。 macOSの割合は少し大きくなる場合があります。