iOSのメモリ管理
retain, releaseをせかせかとやっていたのも過去の話。
今では ARC(Automatic Reference Counting) というコンパイラが参照カウンタ方式でメモリ管理をやってくれる仕組みがあります。
Cに慣れた開発者であれば自分で管理しないことに逆に不安を覚えたかもしれません。
実際, ARCが登場した頃は, 以前のプロジェクトをARCに変換する際の不具合もあったみたいで, ドキドキした覚えがあります。
ARCはガベージコレクションと何が違う?
ARCは一体何者なんでしょうか。
ARC?自動参照カウンタ?それってガベージコレクション(GC)と何が違うの?という疑問もあるかと思います。
ARCとは今まで書いてたretain, releaseをコンパイラが代わりに補完してやってくれるだけの仕組みです。
コンパイル時なので一度だけの静的な最適化です。ガベージコレクション(GC)は言語処理系によって実装されることが多いですが, これをコンパイラにやらせたということでGCのリファレンスカウンタ方式との違いは静的か動的かということかもしれません。
GCのおさらい
そもそも GCはプログラマが手動で管理する場合, メモリはいつまでも解放しないとメモリ消費が増大してしまう一方で, 解放した領域にアクセスするとクラッシュしてしまうという問題を解消するためでした。
特にリアルタイム性に優れた組み込みソフト開発でのメモリリークは重大な問題でした。人知れず動く監視カメラなどでシステムダウンがあったら大変です。しかし, 人命に影響しなかったり, 人間が管理しきれないわけではないレベルの機能要件の場合はGCがなくても解析ツールや長期稼働試験でなんとかなりました。
しかし, スマホアプリケーションとなると, 言語がメモリ管理する仕組みがないと生産性が上がらないというのが背景にあると思います。
基本的なGCアルゴリズムは, リファレンスカウントGCとトレーシングGCの2つに大別されます。
- リファレンスカウントGC : オブジェクトの参照関係が変化する度に, カウントを増減する方式。
- トレーシングGC : ルートからスキャンしていき, 使用されていないオブジェクトを判定する方式。
新しいGCアルゴリズムも2つの組み合わせの事が多いらしいです。
リファレンスカウントGCは常にメモリを切り詰めていく, トレーシングGCは必要なタイミングでスキャンというイメージでしょうか。
ちなみにGCの起源は Javaでなく Lispらしいです。
つまり…どういうことだってばよ?
AplleによるObjective-CのGC標準実装は実現しなかったようですが, C言語のGCライブラリは存在しMacOSアプリではGCをライブラリでサポートしていたようです。
AppleがiOSにおいてGCでなくコンパイラによる処理を決めたのは, ARC以前のコードとの相違をできるだけ小さくしたかったのかもしれません。
また, ARCはソースが見やすくなるだけでなく, C/C++ のようなシビアなメモリ管理からの脱却によってプログラマの負担を減らす意味もあると思いますが, それが全ての点で良いことなのかはわかりません。例えば, 最適化が速度的に手動によるメモリ管理と同等であるかはわかりません。
…というわけで, iOSにはGCがないですがほぼ同等の機能があると言う事です。
iOSの永続的なデータ管理
話変わって, 永続的にデータを保存する場合は様々な選択肢があります。
(個々のアプリに割り当てられた領域についてなのでアプリを消したら消えます。ここでいう永続的とは電源を消しても消えないことを指します)
選択肢 | メリット | デメリット |
CoreData | 視覚的/高機能 | 使いこなすのに時間がかかる |
SQLite | SQLの知識あれば導入は容易 | 記述がC++なので個人差あり |
NSUSerDefault | KVO/簡単操作 | 中規模以上のデータには向かない |
PropertyList | 設定管理 | 中規模以上のデータには向かない |
ここで注意すべきは CoreData も結局は SQLite で保存している点。 CoreData は Objective-C ユーザに使いやすくしているだけなので, すでにSQLに慣れている人はあえて Coredata を選択する必要はないかもしれないです。
特に, クロスプラットフォーム開発が主流になりつつある今では Android でも SQLite は使えるので統一したほうが開発者の負担は小さいかもしれません。
PropertyListの実体はAplle定義のXMLです。アプリ内の設定データなど定数管理に使用し, ユーザによって変更されるケースには使わない方がいいと思います。writeもできますがシミュレータ以外だと実機ごとのIDを取得しないといけないのでめんどいです。
おわりに
個人的には, めんどくさくてもコンパイラによる自動メモリ管理の仕組みや CoreData の裏で見えにくい SQLite の仕組みに目を通しておく事は長期的に有用な事だと思います。実はそっちの知識の方が長くいきてくるからです。