4
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

iOS メモリ管理のまとめ

Posted at

#はじめに
普段iOSアプリを開発する際は、メモリ管理を意識することがほとんどありません。
しかし、こういったトリビア的なものも知っておくと後々便利になることもありますし、裏でどんなことを行なっているのかある程度知ることができます。

結構ためになると思うので共有してみたいと思いこの記事を書きました。

認識が間違っている箇所があったら、是非指摘していただけたらと思います。

#メモリ管理モデル
1つのオブジェクトは1つ以上の所有者を持ち、少なくとも1つの所有者を持つ間は、オブジェクトは存在し続けます。
所有者がいなくなった場合はランタイムシステムが自動的にオブジェクトを破棄します。
受け取ったメソッドはメソッドのスコープ内で有効でスコープから外れると参照カウントが減るようになっています。

#参照カウントというモデルについて
前知識としてまず、メモリ管理モデルの参照カウントについてお話します。
iOSはこのメモリ管理モデル(参照カウント)を採用しております。参照カウントの基本モデルは、NSObjectのプロトコルで定義されているメソッド命名規約から成っており、これはオブジェクトを参照するとカウント数が1増え、参照し終えると1減ります。最終的に0になるとNSObjectが自動的に確保したメモリを破棄します。

iOSの過去のメモリ管理方法

iOSアプリのメモリ管理ではMRR(Manual Retain Release)というメモリ管理方法が用いられていました。これは自分でメモリ領域を確保したり、解放したりするメモリ管理メソッド(new, retain, release, alloc等)を自分で加えなければいけませんでした。(本当に便利になりませんでした。)

iOSの現在のメモリ管理方法ARCについて

現在ではARC(Automatic Reference Count)というメモリ管理方法が主流で、MRRと同じで「参照カウント」を用いられているのですが、メモリ管理メソッド(retainとかリリース、オートリリースとか)をソースコードに書く必要が無く、コンパイル時に必要なメモリ管理メソッドを挿入するようになっているのです。
なので、コンパイル途中のコードを見るとメモリ管理メソッドが加えられたコードを見ることができると思います。

#そもそもメモリ管理とは
メモリを割り当てて、使い、必要がなくなったら解放することがメモリ管理です。
ARC方式だとあまり意識しなくて良いのですが、油断が禁物です。
循環参照だったり、繰り返し処理などで、常に新しいviewをaddSubviewしたり、closureなどによってメモリが解放されなくなったすると、メモリが圧迫されます。
これは過去のMRR方式と現在のARC方式のメモリ管理方法両方で直面することがある問題ですので、是非気をつけましょう。

スコープの中で必要がなくなった変数がどのように解放されるか注意しておくとよいかもしれません。

#メモリ管理でよく起こった問題
##使用中のデータを解放、上書き等してクラッシュする 
まだ使用中のデータを解放、上書きしてメモリの内容が破損しクラッシュにもつながります

例えば、APIにリクエストを送ってレスポンスが帰ったときに、処理をさせたい場合があるとします。
そんな時にclosureを使って、インスタンス変数に帰ってきた値を入れるとしましょう。

API.request(parameters: parameters, completion: { (result) in
  self.requestResult = result
})

この場合、APIのレスポンスが返って来る前に、selfが解放されたりすると、クラッシュします。
解決するには、弱参照を使いましょう。(デフォルトの参照方法は強参照。)

API.request(parameters: parameters, completion: { [weak self] (result) in
  guard let optionalSelf = self else { return }

  optionalSelf.requestResult = result
})

##メモリリーク
割り当てたメモリが不要になったのに、解放されないことで、メモリのリソースが消えて行きクラッシュしてしまいます。

例えば、ボタンを押すたびに、新しいviewを追加するとします。

@objc private func pushButton(_ sender: UIButton) {
 let view = hogeView()
 addSubView(hogeView)
}

こうすると新しいviewがどんどん追加されていって、メモリを圧迫していくので、古いものを解放する必要がります。
removeFromSuperviewを使ってちゃんと削除しましょう。

#終わりに
必要以上にメモリを使わないプログラムは高品質なプログラムに繋がりますので、常に意識しましょう!

4
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?