前回は Automatic Reference Counting
の基本動作を具体的に Objective-C を使って見ていきましたけれど、今回はその動きを The Swift Programming Language に沿って Swift 目線で再確認していく感じの回になりそうです。かつては誰もが知って適切に扱えるべき基礎的な分野でしたけれど、今みたいに空気のような存在になると逆になかなか理解のしにくい感じもするので、ゆっくりと眺めていってみますね。どうぞよろしくお願いします。
——————————————————————————— 熊谷さんのやさしい Swift 勉強会 #210
00:00 開始 00:26 前回の所感 02:14 かつては難しく感じた機能 05:50 所有権で気になるところ 07:40 消費して扱う consuming 08:31 右辺値と std::move 11:39 内部バッファーを複製せずに加工できる 13:04 API を提供するときに不可欠かもしれない 15:51 ARC の仕組み 18:12 不用意にメモリーを占有する機会の減少 19:34 チャンクメモリーってよく使う言葉? 20:44 Subversion の思い出 21:24 同じ言葉なら同じ意味とは限らない 22:07 C 言語の map は連想配列 23:55 天地創造ってすごいよね、という話 27:48 強参照による生存管理 28:51 クロージング ———————————————————————————
Transcription & Summarize : 熊谷さんのやさしい Swift 勉強会 #210
はい、では始めていきますね。今日はARC(Automatic Reference Counting)の仕組みについて説明します。これは「The Swift Programming Language」に記載されているセクションに基づいています。
前回はObjective-CでARCを解除して、メモリ管理を手動で行う方法について説明しました。これをやってみると、参照カウント管理をしないとメモリの解放ができないことがよく分かりました。あれは基礎中の基礎であり、知らないとまともにコードが書けないレベルの話ですが、逆に言えばそれほど難しい概念でもありません。ARCの登場によって、自動でメモリ管理をしてくれるようになり、スコープを抜けたら解放されるという簡単な話で済むようになりました。
しかし、改めて考えると、参照カウントなどの概念が理解しづらいと感じることもあります。例えば、関数型の考え方やクロージャの使い方が一度難しく感じたことも、今では当たり前に使えるようになっています。時代によって、どんな技術や概念が難しいと感じるかは変わるものです。
特に最近は、オブジェクト指向プログラミング(OOP)が普及してきて、初心者でもクラス設計やポリモーフィズムを普通に使えるようになりました。以前はC++でオブジェクト指向を学ぶのに相当苦労しましたが、今の時代の若いプログラマはそれを速やかに習得できるようになっています。これも技術の進歩とそれを支える教育の成果なのかもしれません。
会話が少し脱線しましたが、戻りますと、リファレンスカウンティングは忘れられがちな技術ですが、忘れるわけにはいきません。最近では、メモリオーナーシップ(Memory Ownership)という概念も出てきており、この勉強会でも話題にしたことがあります。メモリオーナーシップの概念はARCとはまた異なり、自動ではなく明示的なメモリ管理が求められる場合もあります。
以上が、今日の説明の内容となります。引き続き、Swiftの他の特徴についても深掘りしていきますので、質問があれば遠慮せずにどうぞ。 Swiftの新しいメモリーオーナーシップについてですが、最近アクセプトされたプロポーザルがあります。それは、ボローイング(参照渡し)とコンシューミング(ムーブ渡し)に関するものです。C++に慣れている人なら、参照渡しとムーブ渡しの概念にイメージが付くと思います。コンパイラがうまく支援してくれるため、それほど敷居が高くないのではないかと考えていますが、まだ試していないので確かではありません。
特にコンシューミングの方が、理解には少し難しいかもしれません。コンシューミングとは、一度渡したらその参照を自分自身ではもう使わない前提で、「破壊して解放しても構わない」という渡し方です。C++で言うところのムーブ渡しに近い概念です。例えば、ある関数が配列を返すとします。その関数内で配列のインスタンスを生成し、その戻り値を返します。戻り値の配列インスタンスが代入されるとき、通常は右辺の値を左辺にコピーします。
このイコール演算で、Swiftの構造体では右辺の値を左辺の値にコピーします。このとき、「右辺の値を左辺にコピーするのだから、右辺の値はいらなくなる」と考えられます。これがコピーオンライトの基本動作です。コピーした後、右辺のインスタンスを捨てるのはもったいないので、その場合の最適化策も考えられています。C++のように、右辺値をムーブとして扱ってそのまま左辺に渡せば、コピーのオーバーヘッドがなくなります。
右辺値のムーブ渡しを行うことで、後々のパフォーマンス向上が期待できます。この概念を利用することで、例えば関数の戻り値を簡単に渡すとき、コピーせずにムーブ渡しを行うことが可能になります。これにより、より効率の良いメモリ管理が実現できるのです。
Swiftの新しいオーナーシップシステム、特にコンシューミングの考え方を取り入れることで、従来のオートマティックリファレンスカウンティング(ARC)とはまた違った、もう少し専門的な知識が必要になってくるかもしれません。このプロポーザルがアクセプトされたことで、今後のSwiftのプログラムの書き方や最適化方法に影響を与えるでしょう。 Swift言語についての勉強会の内容ですので、まずはそこをしっかり押さえていきましょう。現在の技術は急速に進化しており、みんなを引っ張りながら進む部分もあります。そのため、技術の変化に対してそれほど怯える必要はないかもしれません。
さて、Automatic Reference Counting(ARC)の仕組みについて見ていきましょう。
ARCは、新たなクラスのインスタンスを作成するたびに、そのインスタンスの情報を格納するためのメモリブロックを割り当てます。具体的には、インスタンスに関連付けられたプロパティの値と共にインスタンスの型情報がそのメモリブロックに保持されます。
C++のような他の言語では、ポインタの前に型情報が入っていることがあるという話もありますが、これは余談です。必要なくなったインスタンスのメモリはARCが開放し、そのメモリを他の目的で利用できるようにします。これにより、クラスのインスタンスが不要になった場合にメモリを占有し続けることがなくなります。
前回の勉強会で話したように、ARCがなかった場合は参照カウントを適切に管理しないと、メモリが解放されないことがありました。しかし、ARCの導入によってそのような問題が大幅に減少しました。特に、クロージャの登場により、Swiftではメモリの不適切な占有がさらに減少しました。クラスではないためARCは関係ありませんが、クロージャのおかげで全体的にメモリ管理が自動化され、効率的になっています。
ちなみに、メモリブロックという言葉についてですが、原文では「チャンクオブメモリー」と表現されています。私には「チャンクメモリー」という言葉はあまり馴染みがありませんが、一部の開発者の間では一般的に使われる表現のようです。発音や用語の違いはありますが、意味としては同じですので慣れてもらえればと思っています。
以上が、ARCとその関連情報についての説明です。引き続き、Swiftの言語仕様やメモリ管理について深掘りしていきましょう。 そうですね、その方法についてですが、自分が知らなかっただけかもしれません。昔のサブバージョンのことを思い出しましたが、そこで使われていた言葉も今とは異なるかもしれませんね。プログラミング言語にも同じようなことがあるのではないでしょうか。例えば、Swiftを学ぶ際も、他の言語で使われていた言葉の意味と微妙に異なることがあるので、「Swiftのオーナーシップ」は別の概念かもしれないと考えることが大切です。特に、Rustのオーナーシップを知っている人がSwiftでも同じように理解しようとすると、混乱を招くかもしれません。
新しい言葉として受け止めることが重要ですね。たとえば、「リスキル」という言葉も最近よく見かけますが、最初は意味がわからなかったです。学び直しの重要性を再認識することも大切です。人は忘れることで新しい視点を得て、新たな発見をすることができるので、記憶だけに頼らず、学び直しによって得られるものが大きいと感じます。
話を戻すと、今の私たちのトピックは「ARC(Automatic Reference Counting)」ですね。ARCは使用中のインスタンスを追跡する機能を持っています。解放するだけでなく、複数の場所で使っているインスタンスがどこで使われているかを把握する必要があります。解放済みのインスタンスにアクセスするとアプリがクラッシュするので、ARCはこうした問題を防ぐために参照カウントを行い、インスタンスが必要とされている間は解放されないようにします。
具体的には、インスタンスに対して強い参照(ストロングリファレンス)を作り、その数を数えます。この参照が存在する限り、インスタンスは解放されずに保持されるといった仕組みです。
このARCの仕組みについては、スライドも見ながら次回さらに深掘りしていきたいと思います。今日の勉強会はこれで終わりにします。お疲れ様でした。