私はメモリ管理関連のの記事を沢山読います.特にiPhone開発初めてからリークなきクラッシュなきアプリの開発に心掛けた。(モバイルデバイスだから下手に扱うとすぐメモり不足の警告が出されたりするから)
そして、最近ツイッターでこの記事(英文)を見つけたので、簡潔で非常に分かりやすくて日本の方に是非読み頂ければという意思でこの記事を翻訳することにした.(簡潔で非常に分かりやすいですよ!)
私はネイティブではないので、おそらく間違っているところがあるだろうが、エッセンスを理解して頂ければと思う.(→最近友人に見てもらって色々と修正をしてくれたので大感謝!)
えっ!? それは違うよ。メモリ管理について怠け者たちが、大変だと誤解しているんじゃないかなぁ〜。
「さらに他の言語のメモリのオーナーシップ(所有権)、いつリリースするベキかとかを理解する暇はないから」というのは、デベロッパーがめんどくさいな と思っているだけじゃないかなぁ〜。
オブジェクト指向的なメモリ管理の基本は一緒。C++やらObjectPascalでもGCなしの言語なら みんな一緒だ. コンピュータサイエンスの基本の概念でObjective-Cに使うのはほぼささいなことだ.
もし、私は面接官で面接受けている人がそういうこと言ったら、その時点で面接が終了したなぁ、きっと.
しかし、私はGCがあるべきだと思うよ. GCの利点が知らなかったり、分っていないと勘違いしないでください。だから「手動のメモリ管理が大した苦労ではない」というときに あなたはそれを聞いた方がいいと思う。特にObjective-Cでは.
デスクトップのCocoaで開発する(私は結構書くなぁ)ときにCGを使うときがある. プログラムが少し大きくなって、ちょっと調べたり研究したりしているときにCGを使うことが多い。一旦自分が調べたことや試していたことが証明できたらCGを無効にして、全てをリファクタリングするから.
だから、時々GCを使うなら、いつも使えばいいじゃ〜. メモリの管理しなくてもいいから. それにプライベートフレームワークを作って再利用する傾向があるから、それらを動かす為にCGが無効になっているか有効になっているかを見なくてもよくなるし.
Objective-Cの
簡単だね、これより詳細な説明も思いつかないぐらい。しかし、確認の為に
allocしたらオーナーシップを持つことになる.
copyしたらオーナーシップを持つことになる.
newしたらオーナーシップを持つことになる.(newはalloc/initのショットカットだけ)
〜〜〜Jamesさん、もしまだ読んでいたら 既に4分の1を終えているから、もう少し読んだらソフト掛けるようになるゼ〜〜〜
その
その
そして、その
ちなみに、本当はこう直すベキ:
〜〜〜そうだね、GCより遥かに大変だわ! 普段ココアの開発者はどういうふうにやってんの?〜〜〜
上記の例では、
プローパティーの属性は
例を見てみよう.
理由はこれから説明します.
は破壊される(destroyed)また排出させた(drained)ときです。 しかし、それはいつ起きるかを気にしなくても大丈夫です. 正しく
さて、基本のルールに従って行えば オブジェクトを返すメソッドについての疑問がある筈だなぁ。このオブジェクトのオーナーシップを誰が持っているの?ここはオートリリースプールの出番だ.
例えば:
そのNSImageのオーナーシップを誰が持っている? ここはねぇ、この例では、メッセージを送ったオブジェクトはオーナーシップを持つことになる.よって送られた側にreleaseメッセージを送る必要がある。しかし、これは悪い例です.正しいのは次のよう:
Autoreleaseメッセージが最後にあることをに着目しよう.autoreleaseをすると そのオブジェクトがオートリリースプールに追加され poolが破壊されるときに releaseメッセージが送られます.
オートリリースプールの中にさらに別のオートリリースプールはあってもいいので、大量の一時的なオブジェクトを生成するときに便利. そして、もしマルチスレッドの処理をしていれば、新しいスレッド用のオートリリースプールを作る必要があります.
このようなアプリケーションにはメモリ管理は極めて重要な役割で、知らないとうまくいかない場合が沢山あるよ. ありがたいことに CocoaとObjective-Cを使うとそんなに苦労しなくて済む.
そして、最近ツイッターでこの記事(英文)を見つけたので、簡潔で非常に分かりやすくて日本の方に是非読み頂ければという意思でこの記事を翻訳することにした.(簡潔で非常に分かりやすいですよ!)
私はネイティブではないので、おそらく間違っているところがあるだろうが、エッセンスを理解して頂ければと思う.(→最近友人に見てもらって色々と修正をしてくれたので大感謝!)
James Gregoryさんが想像しているよりObj-Cでメモリの管理は簡単
メモリ管理はということばを聞くとスクリプティングする若者たちとJava世界の人が怖がることを私は知っています。でも、実はそんな怖くないんだよ。詳細を言う前にJames Gregoryさんはどう思うかを見てみよう.iPhoneにないの?!。マジ、アップルよ 一体なんだよ!? ガーベージコレックションがなぜそんなに凄いかと説明しようとするギークが沢山いるから、ここは短く言う。すばらしい理由が基本的に2つある.
一つ目、さらに他の言語のメモリのオーナーシップ(所有権)、いつリリースするベキかとかを理解する暇はないから.
二つ目、開発言語の特徴の中で 開発のプロセスを最も加速するガーベージコレックション(GC)の他に思い当たらないからだだ.
アンドロイドにはあるし、ハードウエアに直接関係しているプログラム以外(つまり、ほど全て)の場合は効率的だ。初代のiPhoneにはなかった理由が分かるかもしれないが 最近のiPhoneにない訳ないだろう。メモリ管理があまりにも大変でこれだけで初心者の開発者にiPhoneよりはアンドロイドを始めることを薦めると思うよ.
えっ!? それは違うよ。メモリ管理について怠け者たちが、大変だと誤解しているんじゃないかなぁ〜。
「さらに他の言語のメモリのオーナーシップ(所有権)、いつリリースするベキかとかを理解する暇はないから」というのは、デベロッパーがめんどくさいな と思っているだけじゃないかなぁ〜。
オブジェクト指向的なメモリ管理の基本は一緒。C++やらObjectPascalでもGCなしの言語なら みんな一緒だ. コンピュータサイエンスの基本の概念でObjective-Cに使うのはほぼささいなことだ.
もし、私は面接官で面接受けている人がそういうこと言ったら、その時点で面接が終了したなぁ、きっと.
しかし、私はGCがあるべきだと思うよ. GCの利点が知らなかったり、分っていないと勘違いしないでください。だから「手動のメモリ管理が大した苦労ではない」というときに あなたはそれを聞いた方がいいと思う。特にObjective-Cでは.
デスクトップのCocoaで開発する(私は結構書くなぁ)ときにCGを使うときがある. プログラムが少し大きくなって、ちょっと調べたり研究したりしているときにCGを使うことが多い。一旦自分が調べたことや試していたことが証明できたらCGを無効にして、全てをリファクタリングするから.
だから、時々GCを使うなら、いつも使えばいいじゃ〜. メモリの管理しなくてもいいから. それにプライベートフレームワークを作って再利用する傾向があるから、それらを動かす為にCGが無効になっているか有効になっているかを見なくてもよくなるし.
Objective-Cの
retain
/release
の仕組みは 根本的なメモリ管理とGCの中間的な仕組みだから. C++とかと違って実際にオブジェクトをfreeするわけではない.代わりに「僕は このオブジェクトを使い終えたよ!」と言ってやって あとランライムに任せばいい.基本の4つのルール
Objective-Cを学ぶときに覚えなければルールが4つだけ.- オーナーシップを持つなら、リリースするベキ
- オーナーシップを持たないなら、リリースしちゃダメ
- 自分のクラスの実装で
dealloc
をオバーライドし、オーナーシップを持ったものをリリースするベキ dealloc
を直接呼び出すベキでない
ルール1: オーナーシップを持つとき
Objective-Cでは オブジェクトをallocか、initか、newをしたらオーナーシップを持つころになる.例えば、簡単だね、これより詳細な説明も思いつかないぐらい。しかし、確認の為に
allocしたらオーナーシップを持つことになる.
copyしたらオーナーシップを持つことになる.
newしたらオーナーシップを持つことになる.(newはalloc/initのショットカットだけ)
〜〜〜Jamesさん、もしまだ読んでいたら 既に4分の1を終えているから、もう少し読んだらソフト掛けるようになるゼ〜〜〜
ルール2:オーナーシップを持っていないとき
これはちょっとややこしいんだ. もっていないときはもっていないんだよ. だから、もしalloc/init/newいずれもしていなかったら 持っていないのだ. 次の例を見てみよう:その
NSString
のオーナーシップを持っている?いいえ、alloc
/copy
/new
もしなかったから持っていない.その
NSImage
は?はい、持っている.allocしたから.そして、その
NSData
? これも、いいえ. alloc
/copy
/new
どれもしなかったからだ.ちなみに、本当はこう直すベキ:
〜〜〜そうだね、GCより遥かに大変だわ! 普段ココアの開発者はどういうふうにやってんの?〜〜〜
ルール3と4: dealloc
これは一番大変なところだ. クラスの中にretain
しているインスタンス変数があったら、オブジェクトがdealloc
されるときにそれらのインスタンス変数をrelease
しないといけない.これを示すのは次の例:上記の例では、
SomeObject
は二つのインスタンス変数がある. things
とsomeOtherThings
だ. init
メソッドを見て分かるのは 二つをオブジェクトを生成して、それらをインスタンス変数にアサインしていること.things
に関しては [NSMutableArray arrayWithObjects]
を使っているからretain
を呼び出す必要がある. alloc
/copy
/new
いずれもしない. autorelease
したオブジェクトを返すコンビニエンスメソッドを使ったから 明示的にretain
をしなければいけない. autorelease
したオブジェクトとは何かと思っているかもしれないが それはその次に説明する. とりあえず、上記に説明したメモリ管理の基本だけを頭に入れておいてください.dealloc
メソッドに 生成したオブジェクトをリリースしているだけです。それ以上はなにもありません.(ちなみに、コンビニエンスメソッドとは:
alloc
/init
/new
で始まらないオブジェクトを生成してくれるメソッド。例: [NSArray array]
はコンビニエンスメソッド、[[NSArray alloc] init]
はコンビニエンスメソッドではない。ご存知の通り、コンビニエンスというのは便利の意味を持っていて、release
しなくてもいいから便利という理由で名前持っているらしい. @nacho4d)プローパーティ
Objective-C 2.0はプローパティーを提供してくれる.その詳細はここでは話さないが プローパーティのライフサイクルの中で混乱が生じやすいところがあるので 少しだけ触れたいと思う. ルールは2つのみプローパティーの属性は
retain
またはcopy
だったら dealloc
にnil
をセットするベキ.init
メソッドなどでプローパーティを初期化(init)しているならば autorelease
にするベキ.例を見てみよう.
title
プローパーティに関して NSString
のコンビニエンスメソッドを使って生成しているからautorelease
したオブジェクトが返ってきて 何もする必要がありません.subtitle
プローパティーに関して 私たち、自分で、オブジェクトを新しく(alloc
/init
を使って)生成しているのでautorelease
をする必要があります.理由はこれから説明します.
alloc
/init
を使ってretain
カウントが1になり、subtitle
にアサインすると一個増えるので2になってしまう. autorelease
無しで行うとリテインカウントが決して1に戻らなず メモリリークが発生してしまう. だからautorelease
を入れることで リテインカウントが1個減らしている.オートリリースとは?
実は完全に嘘をついた、完全に.これは実は結構複雑な仕組みで その複雑さはオートリリースプール(Autorelease pool)という形で来ている。それは一体なんだ? オートリリースプールはrelease
メッセージを送られる対象オブジェクトのリストを持っている。いつ送られるかというとプールは破壊される(destroyed)また排出させた(drained)ときです。 しかし、それはいつ起きるかを気にしなくても大丈夫です. 正しく
autorelease
メッセージを送っておければ オブジェクトがちゃんとリリースされるからだ.さて、基本のルールに従って行えば オブジェクトを返すメソッドについての疑問がある筈だなぁ。このオブジェクトのオーナーシップを誰が持っているの?ここはオートリリースプールの出番だ.
例えば:
そのNSImageのオーナーシップを誰が持っている? ここはねぇ、この例では、メッセージを送ったオブジェクトはオーナーシップを持つことになる.よって送られた側にreleaseメッセージを送る必要がある。しかし、これは悪い例です.正しいのは次のよう:
Autoreleaseメッセージが最後にあることをに着目しよう.autoreleaseをすると そのオブジェクトがオートリリースプールに追加され poolが破壊されるときに releaseメッセージが送られます.
(なぜ一個上のが悪い例でこれは良い例かという説明を次にします。
実はメモリ管理の観点から見ると両方とも問題はありません。後でreleaseするか、さきにautoreleaseをするかどっちも一緒です。
しかし、前者の方がCocoaのコンベンションの一つに違反しています。
私は上に書いたコンビニエンスメソッドの定義によると、alloc/init/newで始まるメソッドを送るとオーナーシップを持つことになります。
逆に言えば、そうで始まらないメソッドを送るとオーナーシップを持たないことになりますね。そして、
実はメモリ管理の観点から見ると両方とも問題はありません。後でreleaseするか、さきにautoreleaseをするかどっちも一緒です。
しかし、前者の方がCocoaのコンベンションの一つに違反しています。
私は上に書いたコンビニエンスメソッドの定義によると、alloc/init/newで始まるメソッドを送るとオーナーシップを持つことになります。
逆に言えば、そうで始まらないメソッドを送るとオーナーシップを持たないことになりますね。そして、
getAnImage
は何かの形でオブジェクトを生成しています。かつ、alloc/init/newで始まらないから コンビニエンスメソッドですよね?こう言ったコンビニエンスメソッドが CocoaのコンベンションによるとAutoreleasedオブジェクトを返す筈だよね?、だから コンベンションに従って書くようにしましょう. @nacho4d)オートリリースプールの中にさらに別のオートリリースプールはあってもいいので、大量の一時的なオブジェクトを生成するときに便利. そして、もしマルチスレッドの処理をしていれば、新しいスレッド用のオートリリースプールを作る必要があります.
まとめ
思ったより、そんな怖くないし、複雑ではなかろう. 勿論GCを全然簡単だが、例えGCがあっても手動メモリ管理に向いている処理が沢山があって、手動メモリ管理がメーディアやゲームなどのアプリケーションでもっとも使われている。このようなアプリケーションにはメモリ管理は極めて重要な役割で、知らないとうまくいかない場合が沢山あるよ. ありがたいことに CocoaとObjective-Cを使うとそんなに苦労しなくて済む.
参考文献
実はアップルのドキュメンテーションで十分な筈だが、すばらしい記事が沢山かあって...- MemoryManagement - CocoaDev
- Cocoa memory - www.wooji-juice.com
- Cocoa Memory Management 101 - www.dikant.de
- Memory Management - mattpatenaude.com
- Mastering Cocoa Memory Management on the iPhone - aspirement.com
- The Cocoa Memory Management Rules of the Roat - www.duckrowing.com
0 comments :
Post a Comment