📛

メモリ消費量における 値渡し vs 参照渡し

2024/07/11に公開

TL;DR

参照渡しの方がメモリの消費量は抑えられるが、値を上書きしてしまう可能性があったりとリスクがある。

値渡しと参照渡しのPHPコード例

<?php
// 値渡しの関数
function valuePass($x) {
    $x = 10;
    echo "関数内部(値渡し): $x\n";
}

// 参照渡しの関数
function referencePass(&$x) {
    $x = 20;
    echo "関数内部(参照渡し): $x\n";
}

// メイン処理
$num = 5;

echo "初期値: $num\n";
// 出力: 初期値: 5

// 値渡し
valuePass($num);
// 出力: 関数内部(値渡し): 10
echo "値渡し後: $num\n";
// 出力: 値渡し後: 5

// 参照渡し
referencePass($num);
// 出力: 関数内部(参照渡し): 20
echo "参照渡し後: $num\n";
// 出力: 参照渡し後: 20

参照渡しと値渡しではメモリの消費はどう変わる?

参照渡しと値渡しでは、メモリ消費量は以下の点で異なります。

1. 渡されるデータ量

  • 値渡し: 関数に渡されるのは、変数の値のコピーです。そのため、小さな型のデータであればメモリ消費量に大きな差はありませんが、大きな型のデータや複雑なデータ構造の場合は、値渡しの方が多くのメモリを消費します。
  • 参照渡し: 関数に渡されるのは、変数のメモリ番地(参照)です。つまり、変数の値そのものは渡されないので、メモリ消費量は値渡しよりも少なくなります。

2. データのコピー

  • 値渡し: 関数内で引数の値を変更しても、呼び出し元の変数の値は変わりません。これは、関数内で操作しているのは変数の値のコピーだからです。そのため、値渡しではデータのコピーが発生する分のメモリ消費量がかかります。
  • 参照渡し: 関数内で引数の値を変更すると、その変更はメモリ上の同じアドレスに保存されている値に対して行われるため、呼び出し元の変数に直接反映されます。つまり、データのコピーが発生しないので、メモリ消費量を抑えることができます。

3. オブジェクトの生成・破棄

  • 値渡し: 関数内で渡された引数の値がオブジェクトの場合は、そのオブジェクトに対して生成と破棄の処理が行われます。これは、メモリ上に新しいオブジェクトを作成し、関数終了後に破棄する必要があるためです。オブジェクトの生成・破棄にはコストがかかるため、値渡しの方がメモリ消費量が多くなる可能性があります。
  • 参照渡し: 関数内で渡された引数の値がオブジェクトであっても、オブジェクトのコピーは行われないため、生成・破棄の処理は発生しません。そのため、参照渡しの方がメモリ消費量を抑えることができます。

まとめ

一般的に、参照渡しの方が値渡しよりもメモリ消費量が少ないと言えます。ただし、データの種類や処理内容によっては、値渡しの方が効率的な場合もあります。具体的な状況に合わせて、使い分けることが重要です。

以下は、参照渡しと値渡しを使い分ける際の参考例です。

  • 小さな型のデータを渡す場合: どちらでも問題ありませんが、メモリ消費量を節約したい場合は参照渡しの方が良いでしょう。
  • 大きな型のデータや複雑なデータ構造を渡す場合: 参照渡しの方がメモリ消費量を抑えられます。
  • 関数内で引数の値を変更する必要がある場合: 参照渡しが必要です。
  • オブジェクトを頻繁に渡す場合: 参照渡しの方が効率的です。

なお、参照渡しと値渡しは、プログラミング言語によって実装方法が異なる場合があります。詳細は、それぞれの言語のドキュメントを参照してください。

つまり、大きいデータを引数で渡すときは参照渡しのが良い?

はい、その通りです。大きなデータを引数で渡すときは、参照渡しの方が効率的です。

値渡しでは、渡されるデータのコピーが関数の内部で生成されるため、メモリ消費量が多くなります。一方、参照渡しではデータのコピーが行われず、変数のメモリ番地(参照)が渡されるため、メモリ消費量を抑えることができます。

特に、以下の場合は参照渡しを使用することを強くお勧めします。

  • 引数がオブジェクトの場合: オブジェクトはメモリ上に大きな領域を占める可能性があるため、値渡しによって生成されるコピーはメモリ消費量を大幅に増加させる可能性があります。
  • 引数が頻繁に渡される場合: 値渡しでは毎回データのコピーが行われるため、処理速度が低下する可能性があります。参照渡しであれば、一度参照を渡せば良いので、処理速度を向上させることができます。

ただし、参照渡しを使用する際には、以下の点に注意する必要があります。

  • 関数内で引数の値を変更すると、呼び出し元の変数にも変更が反映される: これは、参照渡しによって関数と呼び出し元が同じデータを参照しているためです。意図しない変更を防ぐために、注意が必要です。
  • 参照渡しは循環参照を引き起こす可能性がある: 複数の変数が互いに参照し合っている場合、循環参照が発生し、メモリリークなどの問題を引き起こす可能性があります。

これらの点に注意した上で、適切に参照渡しを使用すれば、メモリ消費量を抑え、処理速度を向上させることができます。

参照渡しと値渡しを使い分けるための判断基準としては、以下の点を考慮すると良いでしょう。

  • 渡されるデータのサイズ: データが大きい場合は、参照渡しの方が効率的です。
  • 引数の値を変更する必要性: 値を変更する必要がある場合は、参照渡しが必要です。
  • 引数が頻繁に渡される頻度: 頻繁に渡される場合は、参照渡しの方が効率的です。
  • 循環参照のリスク: 循環参照が発生する可能性がある場合は、値渡しの方が安全です。

具体的な状況に合わせて、使い分けることが重要です。

Discussion