【Swift】autoreleasepoolの使い方!ループ処理のメモリ節約方法

この記事からわかること
- Swiftのautoreleasepoolとは?
- メモリの節約方法
index
[open]
\ アプリをリリースしました /
環境
- Xcode:15.0.1
- iOS:17.1
- Swift:5.9
- macOS:Sonoma 14.1
autoreleasepoolとは?
Swiftのautoreleasepool
メソッドはObjective-C時代のメモリ管理を手動で起こっていた際に活用されていた@autoreleasepool
と同じく特定のスコープ内で生成されたオブジェクトを解放する役割を持つようです。
例えばループ内で生成したオブジェクトなどをスコープを抜けるごとに適切に解放することでメモリ消費が増大しないように抑制することができます。
@autoreleasepool {
NSData *data = [[NSData alloc] initWithContentsOfFile:@"path/to/large/file"];
}
しかしSwiftのメモリの仕組みであるARC(Automatic Reference Counting)の導入から手動でのメモリ管理ではなく、自動でメモリの確保と解放を行なってくれるようになりました。ARCではメモリを解放するタイミングはガーベジコレクションの要領でそのメモリへの参照が0になったタイミングで行うようです。
それでも循環参照などでメモリリークが発生することがあるので、適切なメモリ制御は必要になっています。
Swiftのautoreleasepool
Swiftではループ内で著しく大きなデータを扱う時などに効果を発揮することがあるようです。例えば以下のような場合でしょうか?
- 大量のファイル読み込み
- 画像/動画処理
- 大量のオブジェクトを生成する
実際に以下のようにループ内でインスタンスを生成してみました。以下の処理をautoreleasepool
の有/無で実験してみたところ以下程度であれば、メモリは両者に違いはなく、autoreleasepool
有ではCPU使用率が逆に高まってしまう結果になりました。
for _ in Array(1...1000000) {
autoreleasepool {
let test = Test()
let test2 = Test()
}
}
- autoreleasepool有: CPU 40~55% メモリ 20~30MB
- autoreleasepool無: CPU 20~30% メモリ 20~30MB
画像を加工する処理を試してみる
次に重たい処理として画像を合成する処理を挟んでみます。
for _ in Array(1...1000000) {
autoreleasepool {
let image = UIImage(named: "AppIcon")
// 独自実装の画像に文字を追加するメソッド
imageStampPlacement(img: image ?? UIImage(), stampText: "Hello")
}
}
この結果では有りの方はメモリ消費量がずっと30MBなのに対し、無しの方は処理が走っている間にメモリ消費量がずっと鰻登りに上昇していきました。画像加工のような重たい処理の場合は有りの方が大きくメモリ消費を抑えられていることがわかりました。
autoreleasepool有

autoreleasepool無

- autoreleasepool有: CPU 85~99% メモリ 20~30MB
- autoreleasepool無: CPU 85~99% メモリ 上昇し続ける
autoreleasepool
はメモリ消費を抑えることができるメソッドですが使いどきを見極めることが大事なようです。
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。