SSブログ

mailpeeper-tlsのバグ(Objective-Cでのメモリリーク) [プログラミング]

姿勢のいい女の人に惹かれる。自分がめっちゃ猫背だからだろうか。何か姿勢がいい人はエロティックな気がするんですけど、そう感じるのは自分だけかなぁ。ちょっと海老反りがかった腰の所が好き。始めから脱線したけど、Objective-Cの話。


・メールを受け取った後に、再度新規メールがあるとハングしやすい気がする。
・本格的にメモリーリークが大きくなってきた。

メモリーリークの方は元々あったのだけれど、以前は実行サイズが20MBくらいで済んでいたのですが、30MBくらいの大きさになって、メーラーでアクセスしてダウンロードしてきた後、メール情報をさっくり消しても実行サイズが大きなままで、明らかにメモリが漏れてる感じなんですが、きっちりメモリの後始末をしようとすると、アプリごと落ちちゃったりする。どないせいっちゅうねん。オブジェクトをリリースするやり方とタイミングが違うんだろうなぁとは思うけど、これは根本的に勉強し直さなきゃダメかも。

もう、実装できそうな所はやっちゃった(Growlと着信音とか)ので、後はそこを直せばほぼ完成なんですけどね。最後のひと足掻き。

 
メニュー>ビルド>build and analyzeをしてみて、どこが漏れているのか調べたんだけど、どうにも合ってないような気がして、むりやりオブジェクトをreleaseしちゃったりすると、アプリケーションごと落ちちゃったりします。

とりあえず、allocとかしている所をチェックして、ブレークさせながらきちんと開放されているか見るしかないかもしれません。明らかに動作とともに使用メモリが増えているので、どこがどうみたいな山はかけられそうもないのが辛いですね。autoreleaseとかの仕組みが全然分かってないものだから、かなり基本から知っておかないとキツいかな?



面倒だからガベージコレクション利用に変更しようかな、と思って、Objective-C 2.0に変換みたいのがあったので使ってみたら、while文をfor文に変えるぐらいしかやってくれませんでした。そりゃ、機械的に置き換え程度しか出来ないだろうから、メモリ操作の部分などは変換してくれるはずもない。そもそも2.0でガベージコレクションが導入されたんだっけかな。たまたま2.0の改変の時に入れ込んだだけなのかな。


http://hamasyou.com/blog/archives/000383

Objective-C のオブジェクト初期化メソッドのルールに、
init〜 で始まるメソッドで確保したオブジェクトは自身で解放する必要がある、
というものがあります。

例えば次の例のような場合は、自分で責任をもって release する必要があります。

NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:@"hoge", @"foo", nil];
 
[array release];

init〜 で始まらないメソッドで確保したオブジェクトは自身で解放してはいけません。

NSMutableArray *array = [NSMutableArray arrayWithObjects:@"hoge", @"foo", nil];


>あ、自分で開放しちゃいけないんだ。initというよりか、allocは開放しなきゃダメでしょ、と思ってた。initっていうよりも中でallocやらinitやらを呼んでいるようなメソッド[NSString string]みたいなココアのドキュメントに書かれている、+が付いたメソッドとかは、開放しなくちゃいけないものだと思っていた。何だかどれを解放していいか分からなくなってきた。initが付いていないメソッドは、自分で解放しなくてもいいのかな。


んー、init〜はAppleのXcodeのドキュメントにも書いてあるね。

Subclasses shouldn’t override alloc to include initialization code. Instead, class-specific versions of init... methods should be implemented for that purpose. Class methods can also be implemented to combine allocation and initialization, similar to the new class method.

init〜のメソッドはallocをオーバーライドできないので、代わりに作るみたい。


 http://www.textdrop.net/google-styleguide-ja/objcguide.xml

>というかGoogleはObj-Cなんて使っているものなのかね。あ、iPhoneアプリとか?

・生成時にautoreleaseすることを推奨

一時的なオブジェクトを新しく生成するときには、
そのメソッドの終わりの方で個別に release するのではなく、
オブジェクトの生成と同じ行で autorelease しましょう。

ほんの少し遅くなりますが、うっかり release を消したり、
release の前に return することで、メモリリークが発生してしまうのを
防ぐことができます。

// 避けよう(やむを得ないパフォーマンス上の理由がない限り)
MyController* controller = [[MyController alloc] init];
// ... リターンするかもしれないコード ...
[controller release];

// 望ましい
MyController* controller = [[[MyController alloc] init] autorelease];


>というか、自分でalloc, initするコードとか、ほとんど書いてないしなぁ。既存のソースを見てみようかな。そもそもautoreleaseってメソッドがどうなってんだかが分かってない。オートでやってくれる分にはいいけど、的確に解放される位置を理解しないと気持ち悪いし、本当に直した事にならない。自動変数的にスコープが終わると消えるのかな。消したくないときはretainしておくってこと?


・autoreleaseしてからretainする

オブジェクトの代入には、autorelease してから retain する、
というパターンを使いましょう。

新しいオブジェクトを変数に代入するときには、メモリリークを
起こさないよう、まず古いオブジェクトを解放する必要があります。
これには「正しい」やり方がいくつかあります。
ここでは、「autoreleaseしてからretainする」という方法を選びました。
なぜなら、間違いにくいためです。
タイトループでは、autorelease pool がいっぱいになって、
効率が少し悪くなることに注意してください。
それでも、このトレードオフは許容できると考えました。

- (void)setFoo:(GMFoo *)aFoo {
  [foo_ autorelease];  // |foo_| == |aFoo| であれば、deallocしない
  foo_ = [aFoo retain]; 
}




いまいちよく分かっていませんが、メモリーリーク探索の方針を立ててみる。


・現在、解放されるべき時に解放されてないっぽい状況を探す。
(メールをチェックして何通かメールが来ていた後に、メールボックスが空になっていた時など)

・initを呼んでいる、またはinitが頭文字になっている場所をチェックする。

・動作させてinitが発動して、releaseされていない所は、releaseさせる。

・retainで解放させないようにしていない部分は、retainとreleaseを使うようにする。

・オブジェクトを他のメソッドに渡さないような、すぐに消す場合では、同じ行でautoreleaseを使うようにする。


こんなものでしょうか。

言うは簡単、行なうは難し、ですね。

タグ:freesoft
nice!(0)  コメント(0) 
共通テーマ:パソコン・インターネット

nice! 0

コメント 0

コメントを書く

お名前:[必須]
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。