ライフタイムとは?|プログラミングにおけるライフタイムについて3分でわかりやすく解説します【プログラミング初心者向け】

用語解説

こんちには。キノコードです。
このレッスンでは、 ライフタイムについて説明をします。

▼ YouTube動画はこちらからどうぞ。

この記事の執筆・監修

キノコード
キノコード

テクノロジーアンドデザインカンパニー合同会社のCEO。
日本最大級のプログラミング教育のYouTubeチャンネル「キノコード」や、プログラミング学習サービス「キノクエスト」を運営。
著書「あなたの仕事が一瞬で片付くPythonによる自動化仕事術」や、雑誌「日経ソフトウエア」や「シェルスクリプトマガジン」への寄稿など実績多数。

ライフタイムとは?

プログラミング言語のRustでは、メモリ管理について、所有権・借用・ライフタイムという独特な仕組みを採用しています。
そのため、開発する上で制約の多いOSやコンパイラなどのソフトウェアを開発することができますし、高速に動くプログラムを書くことができます。
この独特なメモリ管理のライフタイムについて説明します。
ライフタイムとは、「借用において所有者のスコープより長く存続できない」というルールです。。

JavaとRustの比較

この意味をRustとJavaのコードを比較して、ライフタイムの特徴を見ていきましょう。
借用については別の解説動画をご覧ください。
まず、Javaで参照型の配列を作っていきましょう。

public static void main(String[] args) {

    int[] a; //1.変数aを宣言

    {

        int[] b = {5}; //2.変数bを初期化

        a = b; //3.aにbの参照をコピーする

        b = null; //4.ここでbのリソースが解放「されない」

    }

    System.out.print(a[0]); //5.aを参照

}

-結果- 5

変数aを宣言
次にコードブロックを書きます。
コードブロック内にローカル変数を宣言すると、そのコードブロック内のみローカル変数を使うことができます。
次に、配列bを宣言して初期化。
aにbの参照をコピーします。
bにnullを代入します。
このコードブロックの外にaが表示されるプリントラインを記述しましょう。
bはコードブロック内でのみ使えるはずです。
つまり、bのリソースは解放されているはずです。
bの参照をコピーしたaはどうなるのでしょうか?
コンパイルして実行します。
5が表示されました。
Javaの場合はaを参照できます。
これは、なぜでしょうか?
Javaの場合は「全ての参照がなくなるまで、メモリにデータを残し続ける」ルールがあるためです。

Javaの場合

public static void main(String[] args) {

    int[] a; //1.変数aを宣言

    {

        int[] b = {5};
        a = b;

        System.out.println("aの番地 : "+a.hashCode());

        System.out.println("bの番地 : "+b.hashCode());

    }

}

では、この時点でデータの入っているメモリの番地を調べてみましょう。
aとbのメモリの番地を表示させてみます。
このように同じ番地になっています。

public class Lifetime03{

    public static void main(String[] args) {

        int[] a;

        {

            int[] b = {5};

            a = b;

            System.out.println("aの番地 : "+a.hashCode());

            System.out.println("bの番地_1回目 : "+b.hashCode());

            b = null;

            System.out.println("aの番地 : "+a.hashCode());

            System.out.println("bの番地_2回目 : "+b.hashCode());

        }

    }

}

bにnullを代入した後はどうなるでしょう?
ここで、bにnullを代入するので、参照できなくなります。
一方、aは参照できます。
実行してみましょう。
変数aの参照が残っているので、メモリにデータが入ったままを維持できています。
一方、bは1回目の番地は表示されますが、2回目の番地は表示されません。
次に、Rustの場合を見てみましょう。
別の解説動画で説明しましたが、Rustの場合は参照ではなく、借用です。

Rustの場合

fn main(){

    let a; // 1.変数aを宣言

    {

        let b = 5; // 2.変数bを初期化

        a = &b; // 3.bをaに借用

    } // 4.ここでbのリソースが解放される

    println!("{}", a); // 5.aを参照

}

-結果-

error[E0597]: b does not live long enough

(直訳:エラー[E0597]: bは十分に長寿ではありません) 

変数aを宣言。
コードブロックの中に、変数bを宣言、初期化。
Rustの場合は、参照ではなく、借用です。
アンパーサンドをつけて、イミュータブル(変更不可)な借用をします。
aを表示させてみましょう。
コンパイルエラーとなりました。
これは、コードブロックを抜けるので、メモリのリソースが解放されるためです。
メモリ解放後のリソースを参照してしまうことになるため、エラーになります。
まとめると、
Javaの場合はコードブロックを抜けても、参照型だと、全ての参照がなくなるまでメモリに残ったままになります。
ちなみに、プリミティブ型の場合は、コードブロックを抜けるとリソースが解放されます。
一方、Rustの場合はコードブロックを抜けたらリソースは解放されます。借用されていてもメモリに残りません。
これが「借用において所有者のスコープより長く存続できない」というライフタイムのルールなのです。
Rustではこのような仕様にして、メモリの安全を確保しているのです。

KinoCode チャンネル

YouTubeで毎日動画配信しています。
動画は3分間なので、
 ・通勤時間
 ・お昼休み
 ・お手すきのとき
 ・寝る前
など手軽に視聴できます。
 
ちょっとしたインプットにどうぞ!
 
▼チャンネル登録はこちらからどうぞ。
未経験からはじめるPython学習「キノクエスト」 キノクエスト
  • スキルアップしたいけど何からはじめればよいかわからない…
  • プログラミングスクールに入りたいけど料金が高い…
  • プログラミングを学んでも業務やキャリアに活かせるか不安…

キノクエストは、このような悩みを持つ方にぴったりのプログラミング学習サービスです。
国内最大級のプログラミング学習系YouTubeチャンネル「キノコード」が提供しているから、未経験者にもわかりやすく質の高い学習体験を実感していただけます。

キノクエスト