初心者PHPプログラマです。
質問させて頂きます。
現在、「PHP Simple HTML DOM Parser」というライブラリを使用して、HTMLパースを行っております。
その際に、循環参照しているので開放しないとメモリリークが起こるという情報を得ました。
そこで初めて循環参照という言葉を知り、調べた結果、
「Aの中でBを呼び」「Bの中でもAを呼ぶ」という認識で覚えました。
しかし、循環参照をしている場合、開放をしてあげないとメモリリークが起きるという流れがよく理解出来ません。
これは一体どういう意味なのでしょうか?
ご存知の方がいらっしゃいましたら、よろしくお願い致します。
No.1ベストアンサー
- 回答日時:
初めまして。
以下、ご回答になってるか分かりませんが、DOMというよりは、一般論的にご回答してみたいと思います。
まず、一般に、メモリは使用が終わったら開放してあげないと、循環参照であるかどうかに関わらず、メモリリーク(メモリが無駄に減り続けること)が起こります。
そして、循環参照とは無限ループ(永久ループともいい、プログラムが終了しないこと)の原因となるものです。
例えば、ご質問の、
「Aの中でBを呼び」「Bの中でもAを呼ぶ」
という処理を実際に展開すると、
Aが呼ばれ→Bが呼ばれ→Aが呼ばれ→Bが呼ばれ→Aが呼ばれ・・・・
というふうに、ABが交互に永久に呼ばれ続けます(AかBの中でプログラムが終了しない限り)。
このとき、AかBの中で、メモリを消費する処理があるとします。(大抵はあります)そのとき、そのメモリが適切に開放されていないと、上記の理由で、AとBが交互に呼ばれる度に、メモリをどんどん食っていくわけで、大抵はあっという間に空きメモリがなくなってしまいます。
また、上記A、Bを「関数A,関数B」と置き換えると、循環参照による無限ループは、スタックと呼ばれるメモリ(の一種)を消費し、いわゆるスタックオーバーフローの原因になり得ます。
以上の点を総合すると、
「循環参照しているので開放しないとメモリリークが起こる」
というよりは、
「メモリは使い終わったら開放しないとメモリリークが起こるが、そのとき循環参照をしていると、メモリがあっという間になくなるような、ひどいメモリリーク(やスタックオーバーフロー)の原因となり得る」
という解釈が正しいのかもしれません。
なお以上は私の理解に基づくもので、間違っている可能性もありますので、ご参考までになさってください・・・。
No.2
- 回答日時:
一点補足させてください・・・
>例えば、ご質問の、
>「Aの中でBを呼び」「Bの中でもAを呼ぶ」
>という処理を実際に展開すると、
>Aが呼ばれ→Bが呼ばれ→Aが呼ばれ→Bが呼ばれ→Aが呼ばれ・・・・
>というふうに、ABが交互に永久に呼ばれ続けます(AかBの中でプログラムが終了しない限り)。
は、下記の方がより正しいと思います:
例えば、ご質問の、
「Aの中でBを呼び」「Bの中でもAを呼ぶ」
という処理を実際に展開すると、
Aが呼ばれ→Bが呼ばれ→Aが呼ばれ→Bが呼ばれ→Aが呼ばれ・・・・
というふうに、ABが交互に永久に呼ばれ続けます。
(AかBの中でプログラムが終了するか、Aの中にBを呼ばないケースや、
Bの中にAを呼ばないケースが存在しない限り)。
※ケースとは、ifやcaseなどでの条件節による場合分けのことです。
No.3
- 回答日時:
なんどもすみません。
。ご質問者様が言われた「開放」は、メモリの開放ではなく、「循環参照から抜ける」という意味だったかもしれないと思いました。
その場合、「開放」とは、
(AかBの中でプログラムが終了するか、Aの中にBを呼ばないケースや、
Bの中にAを呼ばないケースが存在しない限り)。
を指すと思います。
つまり、それにより、再帰を抜けることで、無限ループ(によるスタックオーバーフロー)を防ぐ、という意味合いかもしれません。。
ただ、「開放しないとメモリリーク」というと、やはりメモリの開放をさしていたのではないか・・・などと、一人自問自答しました。。
解決しない場合はよろしければこの点、補足いただけると、他の回答者様の参考になるかもしれません。
ちなみにこんな議論もあるようです(^^;):
http://oshiete.goo.ne.jp/qa/1106226.html
この回答への補足
まずは何度も回答して頂いたこと、本当にありがとうございます。
ほぼ解決しましたが、私の考えも伝えたかったため、補足に記述させて頂きます。
求めていた回答はNo1のものでした!
その後自分なりに調べたのですが、
一般的に変数定義を行った場合、確保されたメモリはスコープを抜けた時点で自動で解放されるが、循環参照を行った場合、ガーベージコレクションが正常に行われず、メモリも解放されず残ってしまうので、手動で解放を行う必要がある。という考えに行き着きました。
ちなみに、解放せずに残ってしまったメモリは、スクリプトが終了しても残ってしまうという記述を今回の件について調べている時にみつけました。
もしそうであるのならば、先日サーバが半日近く止まってしまったのですが、原因は私のせいではないのかと震え上がっています。
今までメモリに関してそこまで深く考えたことは無かったのですが、そういった部分もしっかり考える必要があると考えさせられました。
No.4
- 回答日時:
循環参照は,
$a = array();
$b = array();
$b[] = $a;
$a[] = $b;
のようになっているものを言います。
$b[0]は$aで,$a[0]は$bです。
これは簡単な例ですが,もっと多くのオブジェクトを経由して循環することもあります。
次に,PHPのガベージコレクトは,参照カウント方式が採られています。
この参照カウント方式は,
・カウンタの初期値は0
・変数等に参照されるとカウンタをインクリメント
・ある変数等からの参照がなくなるとカウンタをデクリメント
・カウンタが0になるとメモリを解放する
というものです。
ref) PHP: 参照カウント法の原理 - Manual
http://www.php.net/manual/ja/features.gc.refcoun …
循環参照が発生している状態では,全ての変数から参照されていないにも関わらず,カウンタの値が0になりません。
$a = array(); // array(1) : refcount 1 ($a)
$b = array(); // array(2) : refcount 1 ($b)
$b[] = $a; // array(1) : refcount 2 ($a, $b[0])
$a[] = $b; // array(2) : refcount 2 ($b, $a[0])
この状態で関数から抜けても,$a[0]/$b[0]相当の参照が残ります。
すると,これらのメモリは永久に解放されなくなります。
これが循環参照によるメモリリークです。
ただし,マニュアルによるとPHP 5.3から循環参照時もGCさせるアルゴリズムを導入したとあります。
ref) PHP: 循環の収集 - Manual
http://www.php.net/manual/ja/features.gc.collect …
ただし,参照カウント方式のGCを使う場合は循環参照に気をつけるようにした方がよいのは言うまでもありません。
# 言語によっては弱い参照という,カウンタをインクリメントしない参照を用意しているものもあります。
回答ありがとうございます。
循環参照を行った場合に参照カウントの値が0にならなくなる。
よってメモリリークが起こる。
この流れに関しては調べているうちに理解出来たのですが、実際になぜ0にならなくなるのか曖昧なままだったので大変勉強になりました。
本当にありがとうございました!
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Excel(エクセル) エクセル開いたらウィンドウがでました 2 2023/03/28 16:24
- 仕事術・業務効率化 IF関数で時間指定をして、数値を切り上げたいです 1 2022/05/01 23:37
- Excel(エクセル) アウトラインの小計のやり方 1 2023/03/20 11:51
- 食べ物・食材 韓国の主張を真面目に聞いてると、韓国海苔の放射能汚染の心配はしなくていいんでしょうか? 7 2022/07/29 16:50
- カップル・彼氏・彼女 循環器内科医の忙しさについて!!お願いいたします! 2 2022/12/17 01:17
- 呼吸器・消化器・循環器の病気 先日風邪をひき循環器内科を受診時に心雑音があるとの事から心エコーを撮ったところ三尖弁閉鎖不全症の軽度 5 2023/08/28 08:39
- リフォーム・リノベーション 設備屋さん、風呂屋さん、水道屋さん、ガス屋さん教えて下さい。 3 2022/09/18 07:20
- 食べ物・食材 日本で韓国の海産物の輸入が増えてるそうですが……放射能は安全なんですか? 4 2022/12/27 14:54
- 数学 循環小数を既約分数で表し 「分子(m)÷分母(n)」をした際 nによる割り算をn回行う間には、必ずn 3 2023/05/25 11:21
- 呼吸器・消化器・循環器の病気 学校生活での過呼吸の改善法を教えて下さい。 最初は授業中だけでしたが、しだいに友達と喋る時、家にいる 9 2023/02/24 15:56
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
VBAの配列サイズとメモリに関して
-
C言語で、メモリを解放しないで...
-
sil_rew_memのメモリアクセスに...
-
[ちょっと息抜き]メモリを解放 ...
-
VB.netでUSBメモリの固有I...
-
メモリ不足
-
C#で別クラスインスタンスのメ...
-
malloc関数の使い終わった後の...
-
C言語における再帰呼び出しの...
-
メモリアロケーション異常の発...
-
メモリの消費量について
-
メモリのセグメント違反の解決...
-
仮想メモリの増やし方
-
ReadEventLogについて
-
FindFirstFile ハンドル開放
-
<jsp:include>の属性、flushに...
-
エクセル キャッシュメモリー...
-
メモリの解放について VB6 VBA
-
C言語 昇順・降順 ソート
-
ちなみに、for (i = 0; str[i] ...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
C言語で、メモリを解放しないで...
-
VBAの配列サイズとメモリに関して
-
「ヒープサイズの設定」て何?
-
C言語における再帰呼び出しの...
-
エクセルVBA 大容量CSVファイル...
-
動的メモリとexit(C言語)
-
エクセルのメモリ使用状況/Appl...
-
メモリが不足しています(VBA)
-
ファイルマッピング関数で失敗
-
大容量のメモリ確保をスワップ...
-
メモリのセグメント違反の解決...
-
EXCEL-VBAにてADOのレコードセ...
-
メモリ不足
-
エクセル キャッシュメモリー...
-
【C言語】再帰が時間がかかる...
-
C#のOutOfMemoryException発生...
-
closeとメモリの開放について
-
バッチファイルでの実行EXEのメ...
-
メモリの解放について VB6 VBA
-
「memcpy」と「strcpy」について
おすすめ情報