13

iOSでmmapを使用してオーディオファイルを読み取って再生しようとしています。約400MBまでのファイルで問題なく動作します。しかし、500MBのファイルを試してみると、ENOMEMエラーが発生します。

char *path = [[[NSBundle mainBundle] pathForResource: @"test500MB" ofType: @"wav"] cStringUsingEncoding: [NSString defaultCStringEncoding]];
FILE *f = fopen( path, "rb" );
fseek( f, 0, SEEK_END );
int len = (int)ftell( f );
fseek( f, 0, SEEK_SET );

void *raw = mmap( 0, len, PROT_READ, MAP_SHARED, fileno( f ), 0 );

if ( raw == MAP_FAILED ) {
    printf( "MAP_FAILED. errno=%d", errno ); // Here it says 12, which is ENOMEM.
}

なんで?

「700MBは仮想メモリの制限ですが、アドレススペースが断片化されていることがあるため、700MBを取得しますが、チャンクは小さくなります」などの回答に満足しています。(これは単なる推測です、私はまだ答えが必要です)

仮想メモリに関するAppleのドキュメントページには次のように書かれています。

OS Xはバッキングストアをサポートしていますが、iOSはサポートしていません。iPhoneアプリケーションでは、すでにディスク上にある読み取り専用データ(コードページなど)は、メモリから削除され、必要に応じてディスクから再ロードされます。

これは、mmapが物理メモリよりも大きいブロックで機能することを確認しているようですが、それでも、なぜこのような下限に達しているのかを説明していません。

アップデート

  • この答えは興味深いものですが、500MBはそれが言及している700MBの制限をはるかに下回っています。
  • このディスカッションでは、連続したメモリについて説明します。では、メモリの断片化が実際の問題になる可能性がありますか?
  • 256MBの物理メモリを搭載したiPodTouch第4世代を使用しています。
  • 私の研究のポイントは、 「メモリ警告が表示されるまで割り当てを続ける」よりも、ファイルから読み取り専用データをロードするときにメモリを管理するためのより良い方法があるかどうかを確認することです。mmapこれを解決する良い方法のように思えました...

アップデート2

mmapは新しい64ビットバージョンのiOSで完全に機能することを期待しています。64ビットデバイスを手に入れたらテストします。

4

4 に答える 4

2

答えはありませんが、6.0.1 を実行している iPhone 5 でコードをテストしたところ、mmap は 700MB の ISO ファイルで成功しました。したがって、他の要因から始めて、mmap が適切に機能していると仮定します。おそらく、返されたエラーは実際にはメモリが原因ではないか、デバイス自体のメモリが何らかの形で mmap が失敗している場所に使い果たされている可能性があります。デバイスを再起動してみてください。iOS のバージョンによっては、ファイルの最後までシークしたために mmap がファイル全体をマップしようとしている可能性があるのではないかと思います。それをクリーンアップして、代わりに stat を使用してファイルサイズを判断するか、マッピングする前にファイル記述子を閉じてから再度開くことができます。これらはすべて単なるアイデアです。エラーを再現できれば、喜んで修正いたします。

于 2012-11-20T22:34:01.917 に答える
0

NSDataを使用し、ここでmmapに直接触れないでください。

読み取りの失敗の利点を得るには、NSDataReadingMappedを使用してください。NSDataは、低メモリの状況でバイトを解放します

于 2012-11-17T12:29:57.073 に答える
0

通常、利用可能な物理メモリの量は、ファイルを mmap できるかどうかとは関係ありません。これは、私たちが話しているすべての仮想メモリです。iOS での問題は、少なくとも iOS アプリ プログラミング ガイドによると、仮想メモリ マネージャーは読み取り専用セクションのみをスワップアウトすることです...理論的には、利用可能なアドレス空間の量だけに制約されているわけではないことを意味します。ただし、PROT_READ 以外でマッピングしている場合は、使用可能な RAM の量によっても制限されます。http://developer.apple.com/library/ios/#documentation/iphone/conceptual/iphoneosprogrammingguide/TheiOSEnvironment/TheiOSEnvironment.htmlを参照してください。

それにもかかわらず、仮想アドレス空間でのマッピングに十分な大きさの連続したメモリが不足しているという問題が発生している可能性があります。私が知る限り、Apple はユーザー モード プロセスのメモリ上限を公開していません。通常、アドレス空間の上位領域はカーネル用に予約されています。ユーザー モードで使用するメモリが 16 ビットしかない場合があります。

デバッガーでメモリ マップをダンプしないと確認できないのは、プロセスのアドレス空間に多数の共有ライブラリ (dylib) が読み込まれている (Apple の単純なサンプル アプリケーションで 100 以上を数えた) ことです。これらもそれぞれ mmap されており、それぞれが利用可能なアドレス空間を断片化します。

gdb では、'info proc mappings' を使用してメモリ マッピングをダンプできるはずです。残念ながら、lldb で見つけた唯一の同等のものは「イメージ リスト」であり、データ mmap マッピングではなく、共有ライブラリ マッピングのみを示します。

この方法でデバッガーを使用すると、マップしようとしているデータに対して十分な大きさの連続したブロックがアドレス空間にあるかどうかを判断できるはずですが、上限を発見するには多少の作業が必要です (Apple はこれを公開する必要があります!)。

于 2013-02-05T16:16:27.863 に答える