アプリケーションの終了時にリークを処理する必要がありますか、それともシステムに処理させる方が効率的ですか? とにかくシステムがすべてのメモリを再利用すると考えているので、それを解放するための追加の努力はオーバーヘッドになりませんか?
4 に答える
paxdiabloによる引用:
私が知っているすべてのオペレーティングシステムは、割り当てられていたコンベンショナルメモリを再利用します。これは、割り当てが通常、終了時に再利用されるプロセスのプライベートアドレススペースから行われるためです。
私の知る限り、これはiOSにも当てはまります。
ただし、Appleはアプリケーションを拒否する場合があります。通常、メモリリークだけではアプリケーションを拒否する理由はありませんが、バケットをオーバーフローさせるドロップである可能性があります。適切なメモリ管理は良い習慣であり、常に追求する必要があります。
アプリの終了時にすべてのメモリを解放しようとする理由はありません。
これを行うと、CPU サイクルが無駄になります。
確かに、何らかの状態を維持する「シャットダウン」フェーズが必要になる場合がありますが、コードでは、「シャットダウン」コードパスが実行されない可能性があることも想定する必要があります。
システムは、アプリの終了方法に関係なく、アプリが終了すると、アプリケーションによって割り当てられたすべてのリソースを再利用します。
実際、UIKit (iOS) と AppKit (OS X) は両方とも、アプリケーションの終了時に多くのショートカットを使用するため、アプリケーションの終了時にまだ多くのメモリが割り当てられます。これはまさに応答性の理由から行われます。ユーザーがアプリの終了を要求すると、すぐに終了する必要があります。
(そして、プロセスの終了時にリソースを自動的に再利用しない、最新のマルチタスク、タスク分離、OSについては本当に考えられません。)
すべてのアプリケーション (プロセス) は、独自のプライベート メモリ空間で実行されます。オペレーティング システムはこれを管理し、どの「物理」メモリがプロセスに割り当てられているかを常に正確に把握しています。プロセスが終了すると、使用されているすべてのメモリを完全に回復できます。
したがって、アプリケーションが終了する場合は、メモリ管理やクリーンアップを行う必要はありません (ファイル アクセスやネットワーク接続などについても同じことが言えますが、これらの場合はクリーンアップすることが最善の方法かもしれません)。 )。
ただし、アプリケーションがメモリを「リーク」してはなりません。
リークとは、メモリのチャンクを割り当てた後、実行中のプログラム内でメモリへのすべての参照を失うことです。
シングルトンはリークではなく、Instruments はリークとしてフラグを立てません。
したがって、次のようなものがある場合:
static NSString *aStaticString = nil;
+ (void)aFunction {
aStaticString = [[NSString alloc] initWithString:@"aFunction"];
}
これは漏れではありません。したがって、別の機能もあるとしましょう:
+ (void)anotherFunction {
aStaticString = [[NSString alloc] initWithString:@"anotherFunction"];
}
ARC を使用していると仮定すると、これらの関数を呼び出してもリークは発生しません。コンパイラ/ランタイムは NSString の割り当てを管理することを認識しており、aStaticString 変数が変更されると、古いメモリの割り当てを解除します。
これを考えると、どうやってリークを取得しますか?通常、循環参照が原因です。例えば:
+ (void)aBadFunction {
NSMutableDictionary *aDict = [[NSMutableDictionary alloc] init];
[aDict addObject:aDict forKey:@"aCircularReference"];
}
ここでは、aDict が作成 (割り当て) され、それ自体への参照がそれに追加されます。関数が戻ると、プログラムに aDict 変数への参照がなくなるため、メモリがリークします (関数が再度呼び出されると、まったく異なる新しい aDict 変数が作成されます)。通常、ARC は、関数の終了時に aDict の割り当てが解除されるようにしますが、この場合は、オブジェクト自体に参照があるため、できません。
一般に、このような循環参照はより複雑ですが、原理は同じです。
常にメモリを解放する必要がありますが、以下のコメントを参照してください。
違いがあります:
int main() {
int* i = malloc(5);
... // do stuff here
return 0; // i "leaked" here, not that serious, a lot of programmers will skip freeing `i` before return
}
と:
int main() {
int* i;
for(int j = 0; j < 5000; j++)
i = malloc(5); // you leaked 5 bytes 5000 times, very serious, DO NOT DO THIS
// the 24KB here will most likely be reclaimed later, HOWEVER
// what if j changes? what if you have more loops? you may run of memory, especially on an embedded device!
... // do stuff here
return 0;
}
1つのルールに従うだけです。適切なCメモリ管理(Cコーディング規則)を処理するときにオーバーヘッドを気にする必要はありません。
だからこれを行う:
int main() {
int* i;
for(int j = 0; j < 5000; j++) {
i = malloc(5);
... // do stuff with i here
free(i); // you are not leaking anything =D
}
... // do stuff here
return 0;
}