156
PHP GC の話 2015/02/27 87 PHP 勉強会

PHP の GC の話

  • Upload
    y-uti

  • View
    4.012

  • Download
    2

Embed Size (px)

Citation preview

PHP の GC の話2015/02/27

第87回PHP勉強会

なぜ GC の話を?言語処理系の実装を知るのは良い勉強になる

GC はとても面白い◦ 巧妙なアルゴリズム

◦ 高速化のための実装上の (低水準な) 工夫

両方まとめて楽しめる。しかも「本物の」コードで

2015/02/27 第87回 PHP 勉強会 2

なぜ GC の話を?言語処理系の実装を知るのは良い勉強になる

GC はとても面白い◦ 巧妙なアルゴリズム

◦ 高速化のための実装上の (低水準な) 工夫

両方まとめて楽しめる。しかも「本物の」コードで

今日はこちらの話を中心に・・・

2015/02/27 第87回 PHP 勉強会 3

自己紹介内山雄司◦ 株式会社ピコラボ

◦ @y__uti

◦ http://y-uti.hatenablog.jp

好きな話題◦ 機械学習とその周辺分野(ほぼ仕事)

◦ 楽しいけれど数学は不真面目だったので色々つらい

◦ プログラミング言語処理系(学生のときの研究分野/今は趣味)◦ 去年あたり?から HHVM とか PHP7 とか盛り上がっていて楽しい

◦ PHP dis

2015/02/27 第87回 PHP 勉強会 4

目次

GC って何?

GC の仕組み

循環参照を持つゴミの回収

gc_disable() の話

2015/02/27 第87回 PHP 勉強会 5

GC って何?

2015/02/27 第87回 PHP 勉強会 6

Wikipedia によると・・・ガベージコレクション (garbage collection; GC) とは、

プログラムが動的に確保したメモリ領域のうち、不要になった領域を自動的に解放する機能

である。

2015/02/27 第87回 PHP 勉強会 7

http://ja.wikipedia.org/wiki/ガベージコレクション

memory_limitPHP のスクリプトが使えるメモリの上限

2015/02/27 第87回 PHP 勉強会 8

$ cat php.ini...; Maximum amount of memory a script may consume (128MB); http://php.net/memory-limitmemory_limit = 128M...

メモリ不足のプログラム128M を使いきってしまうと?

2015/02/27 第87回 PHP 勉強会 9

<?php$a1 = range(1, 200000); echo '1';$a2 = range(1, 200000); echo '2';$a3 = range(1, 200000); echo '3';$a4 = range(1, 200000); echo '4';$a5 = range(1, 200000); echo '5';

見慣れた?エラー

1234PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 32 bytes) in ... on line 6

プログラム実行の様子

2015/02/27 第87回 PHP 勉強会 10

memory_limit = 128M

array(1, 2, ..., 200000)

プログラム実行の様子

2015/02/27 第87回 PHP 勉強会 11

array(1, 2, ..., 200000)

プログラム実行の様子

2015/02/27 第87回 PHP 勉強会 12

$a1

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

プログラム実行の様子

2015/02/27 第87回 PHP 勉強会 13

$a1

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

プログラム実行の様子

2015/02/27 第87回 PHP 勉強会 14

$a1

$a2

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

プログラム実行の様子

2015/02/27 第87回 PHP 勉強会 15

$a1

$a2

$a3

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

プログラム実行の様子

2015/02/27 第87回 PHP 勉強会 16

$a1

$a2

$a3

$a4

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

プログラム実行の様子

2015/02/27 第87回 PHP 勉強会 17

$a1

$a2

$a3

$a4

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

プログラム実行の様子

2015/02/27 第87回 PHP 勉強会 18

$a1

$a2

$a3

$a4

PHP Fatal Error

変更版のプログラム同じ変数 $a1 に代入する

2015/02/27 第87回 PHP 勉強会 19

<?php$a1 = range(1, 200000); echo '1';$a1 = range(1, 200000); echo '2';$a1 = range(1, 200000); echo '3';$a1 = range(1, 200000); echo '4';$a1 = range(1, 200000); echo '5';

これはメモリ不足にならず実行できる

12345

どうして実行できるの?◦ PHP には「ごみ集め」 (Garbage Collection)の仕組みがあるから

PHP に GC がなかったら

2015/02/27 第87回 PHP 勉強会 20

memory_limit = 128M

array(1, 2, ..., 200000)

PHP に GC がなかったら

2015/02/27 第87回 PHP 勉強会 21

array(1, 2, ..., 200000)

PHP に GC がなかったら

2015/02/27 第87回 PHP 勉強会 22

$a1

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

PHP に GC がなかったら

2015/02/27 第87回 PHP 勉強会 23

$a1

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

PHP に GC がなかったら

2015/02/27 第87回 PHP 勉強会 24

$a1

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

PHP に GC がなかったら

2015/02/27 第87回 PHP 勉強会 25

$a1

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

PHP に GC がなかったら

2015/02/27 第87回 PHP 勉強会 26

$a1

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

PHP に GC がなかったら

2015/02/27 第87回 PHP 勉強会 27

$a1

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

PHP に GC がなかったら

2015/02/27 第87回 PHP 勉強会 28

$a1

PHP Fatal Error

PHP には GC があるので

2015/02/27 第87回 PHP 勉強会 29

memory_limit = 128M

array(1, 2, ..., 200000)

PHP には GC があるので

2015/02/27 第87回 PHP 勉強会 30

$a1

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

PHP には GC があるので

2015/02/27 第87回 PHP 勉強会 31

$a1←もう使わない

array(1, 2, ..., 200000)

PHP には GC があるので

2015/02/27 第87回 PHP 勉強会 32

$a1

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

PHP には GC があるので

2015/02/27 第87回 PHP 勉強会 33

$a1

←もう使わない

array(1, 2, ..., 200000)

PHP には GC があるので

2015/02/27 第87回 PHP 勉強会 34

$a1

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

PHP には GC があるので

2015/02/27 第87回 PHP 勉強会 35

$a1

←もう使わない

array(1, 2, ..., 200000)

PHP には GC があるので

2015/02/27 第87回 PHP 勉強会 36

$a1

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

PHP には GC があるので

2015/02/27 第87回 PHP 勉強会 37

$a1

←もう使わない

array(1, 2, ..., 200000)

PHP には GC があるので

2015/02/27 第87回 PHP 勉強会 38

$a1

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

PHP には GC があるので

2015/02/27 第87回 PHP 勉強会 39

$a1←もう使わない

array(1, 2, ..., 200000)

PHP には GC があるので

2015/02/27 第87回 PHP 勉強会 40

$a1

array(1, 2, ..., 200000)

array(1, 2, ..., 200000)

PHP には GC があるので

2015/02/27 第87回 PHP 勉強会 41

$a1

←もう使わない

array(1, 2, ..., 200000)

PHP には GC があるので

2015/02/27 第87回 PHP 勉強会 42

$a1

array(1, 2, ..., 200000)

PHP には GC があるので

2015/02/27 第87回 PHP 勉強会 43

$a1

Happy!

GC の仕組み

2015/02/27 第87回 PHP 勉強会 44

GC の基本「もう使わない」ことをどのように知るのか?

2015/02/27 第87回 PHP 勉強会 45

<?php$a1 = range(1, 200000);

array(1, 2, ..., 200000)$a1

問題:10000 を表示するには?

echo $a1[9999]; // 10000

GC の基本「もう使わない」ことをどのように知るのか?

2015/02/27 第87回 PHP 勉強会 46

<?php$a1 = range(1, 200000);$a1 = range(200001, 400000);

array(200001, ..., 400000)

array(1, 2, ..., 200000)$a1

問題:10000 を表示するには?

echo $a1[9999]; // 210000

◦ 無理

GC の基本「もう使わない」ことをどのように知るのか?

◦ とても難しい

「もう使えない」ことを知る◦ わりと簡単

◦ 辿れないものは使えない

2015/02/27 第87回 PHP 勉強会 47

array(200001, ..., 400000)

array(1, 2, ..., 200000)$a1

PHP の GC参照カウント方式◦ 自分に入ってくる矢印 (= 参照) の数を記録しておく

◦ 矢印の数が 0 になったら「もう使えない」

2015/02/27 第87回 PHP 勉強会 48

PHP の GC参照カウント方式◦ 自分に入ってくる矢印 (= 参照) の数を記録しておく

◦ 矢印の数が 0 になったら「もう使えない」

2015/02/27 第87回 PHP 勉強会 49

$a1 = new MyList();

1$a1

PHP の GC参照カウント方式◦ 自分に入ってくる矢印 (= 参照) の数を記録しておく

◦ 矢印の数が 0 になったら「もう使えない」

2015/02/27 第87回 PHP 勉強会 50

$a1->next = new MyList();

1$a1 1

PHP の GC参照カウント方式◦ 自分に入ってくる矢印 (= 参照) の数を記録しておく

◦ 矢印の数が 0 になったら「もう使えない」

2015/02/27 第87回 PHP 勉強会 51

$a1->next->next = new MyList();

1$a1 1 1

PHP の GC参照カウント方式◦ 自分に入ってくる矢印 (= 参照) の数を記録しておく

◦ 矢印の数が 0 になったら「もう使えない」

2015/02/27 第87回 PHP 勉強会 52

$a2 = new MyList();

1$a1 1

$a2

1

1

PHP の GC参照カウント方式◦ 自分に入ってくる矢印 (= 参照) の数を記録しておく

◦ 矢印の数が 0 になったら「もう使えない」

2015/02/27 第87回 PHP 勉強会 53

$a2->next = $a1->next;

1$a1 2

$a2

1

1

PHP の GC参照カウント方式◦ 自分に入ってくる矢印 (= 参照) の数を記録しておく

◦ 矢印の数が 0 になったら「もう使えない」

2015/02/27 第87回 PHP 勉強会 54

$a1->next->next->next = new MyList();

1$a1 2

$a2

1

11

PHP の GC参照カウント方式◦ 自分に入ってくる矢印 (= 参照) の数を記録しておく

◦ 矢印の数が 0 になったら「もう使えない」

2015/02/27 第87回 PHP 勉強会 55

$a1->next->next->next->next = $a1->next->next->next;

1$a1 2

$a2

2

11

PHP の GC参照カウント方式◦ 自分に入ってくる矢印 (= 参照) の数を記録しておく

◦ 矢印の数が 0 になったら「もう使えない」

2015/02/27 第87回 PHP 勉強会 56

$a2 = new MyList();

1$a1 2

$a2

2

10

1

PHP の GC参照カウント方式◦ 自分に入ってくる矢印 (= 参照) の数を記録しておく

◦ 矢印の数が 0 になったら「もう使えない」

2015/02/27 第87回 PHP 勉強会 57

$a1 = new MyList();

1$a1 1

$a2

2

1

1

PHP の GC参照カウント方式◦ 自分に入ってくる矢印 (= 参照) の数を記録しておく

◦ 矢印の数が 0 になったら「もう使えない」

2015/02/27 第87回 PHP 勉強会 58

unset($a1);

0 1

$a2

2

1

1

PHP の GC参照カウント方式◦ 自分に入ってくる矢印 (= 参照) の数を記録しておく

◦ 矢印の数が 0 になったら「もう使えない」

2015/02/27 第87回 PHP 勉強会 59

unset($a1);

0

$a2

2

1

1

PHP の GC参照カウント方式◦ 自分に入ってくる矢印 (= 参照) の数を記録しておく

◦ 矢印の数が 0 になったら「もう使えない」

2015/02/27 第87回 PHP 勉強会 60

unset($a1);

$a2

1

1

1

PHP の GC参照カウント方式◦ 自分に入ってくる矢印 (= 参照) の数を記録しておく

◦ 矢印の数が 0 になったら「もう使えない」

2015/02/27 第87回 PHP 勉強会 61

unset($a1);

$a2

1

1

1

これは?→

循環参照を持つごみの回収

2015/02/27 第87回 PHP 勉強会 62

循環参照参照カウント方式の弱点◦ 参照関係に循環があると矢印の数が 0 にならないまま辿れなくなる

◦ だんだん溜まっていき最後にはメモリ不足になってしまう

PHP 5.2 まで◦ 辿れなくなる前に自分で unset しなければいけなかった

◦ つらい・・・普通バグる

2015/02/27 第87回 PHP 勉強会 63

$a2

1

1

1

循環参照の GCPHP 5.3 以降◦ 循環参照の問題にも対応

文献

◦ Concurrent Cycle Collection in Reference Counted Systems

◦ http://researcher.watson.ibm.com/researcher/files/us-bacon/Bacon01Concurrent.pdf

◦ http://www.ibm.com/ にアクセスして論文名でサイト内検索すれば見つかる

2015/02/27 第87回 PHP 勉強会 64

http://php.net/manual/ja/features.gc.collecting-cycles.php

循環参照の GCPHP 5.3 以降◦ 循環参照の問題にも対応

たとえば以下の状態から・・・

2015/02/27 第87回 PHP 勉強会 65

1$a1

$a2

2

2

1

1

1

2

2

2

循環参照の GC - Release

参照カウントが 0 になった場合◦ ゴミなので回収する(通常の参照カウント方式)

2015/02/27 第87回 PHP 勉強会 66

unset($a1);

0

$a2

2

2

1

1

1

2

2

2

循環参照の GC - PossibleRoot

参照カウントが減ったがまだ 0 ではない場合◦ ゴミができてしまった「かもしれない」

◦ 候補として覚えておく

2015/02/27 第87回 PHP 勉強会 67

$a2

1

2

1

1

1

2

2

2

やばい奴ら

循環参照の GC必要に応じて候補をチェックする◦ メモリ不足になった

◦ gc_collect_cycles() が呼ばれた

◦ 覚えきれなくなった (上限 10,000)

2015/02/27 第87回 PHP 勉強会 68

$a2

1

2

1

1

1

2

2

2

やばい奴ら

循環参照の GCはじめに◦ この図の全体を見渡すと・・・

2015/02/27 第87回 PHP 勉強会 69

$a2

1

2

1

1

1

2

2

2

やばい奴ら

ここはゴミ→

循環参照の GC - MarkRoots

候補のオブジェクトを「灰色」にする

2015/02/27 第87回 PHP 勉強会 70

$a2

1

2

1

1

1

2

2

2

やばい奴ら

循環参照の GC - MarkGray

矢印を辿りながら◦ 参照カウントを 1 減らす

◦ 辿ったオブジェクトを「灰色」にする

2015/02/27 第87回 PHP 勉強会 71

$a2

1

2

1

0

1

2

2

2

やばい奴ら

循環参照の GC - MarkGray

矢印を辿りながら◦ 参照カウントを 1 減らす

◦ 辿ったオブジェクトを「灰色」にする

2015/02/27 第87回 PHP 勉強会 72

$a2

1

2

1

0

1

1

2

2

やばい奴ら

循環参照の GC - MarkGray

矢印を辿りながら◦ 参照カウントを 1 減らす

◦ 辿ったオブジェクトを「灰色」にする

2015/02/27 第87回 PHP 勉強会 73

$a2

1

2

1

0

1

1

1

2

やばい奴ら

循環参照の GC - MarkGray

矢印を辿りながら◦ 参照カウントを 1 減らす

◦ 辿ったオブジェクトを「灰色」にする

2015/02/27 第87回 PHP 勉強会 74

$a2

1

2

1

0

1

0

1

2

やばい奴ら

循環参照の GC - MarkGray

矢印を辿りながら◦ 参照カウントを 1 減らす

◦ 辿ったオブジェクトを「灰色」にする

2015/02/27 第87回 PHP 勉強会 75

$a2

1

2

1

0

1

0

1

1

やばい奴ら

循環参照の GC - MarkGray

矢印を辿りながら◦ 参照カウントを 1 減らす

◦ 辿ったオブジェクトを「灰色」にする

2015/02/27 第87回 PHP 勉強会 76

$a2

1

2

1

0

1

0

0

1

やばい奴ら

循環参照の GC - MarkGray

矢印を辿りながら◦ 参照カウントを 1 減らす

◦ 辿ったオブジェクトを「灰色」にする

2015/02/27 第87回 PHP 勉強会 77

$a2

1

2

1

0

0

0

0

1

やばい奴ら

循環参照の GC - MarkGray

矢印を辿りながら◦ 参照カウントを 1 減らす

◦ 辿ったオブジェクトを「灰色」にする

2015/02/27 第87回 PHP 勉強会 78

$a2

1

1

1

0

0

0

0

1

やばい奴ら

循環参照の GC - MarkGray

矢印を辿りながら◦ 参照カウントを 1 減らす

◦ 辿ったオブジェクトを「灰色」にする

2015/02/27 第87回 PHP 勉強会 79

$a2

0

1

1

0

0

0

0

1

やばい奴ら

循環参照の GC - MarkGray

矢印を辿りながら◦ 参照カウントを 1 減らす

◦ 辿ったオブジェクトを「灰色」にする

2015/02/27 第87回 PHP 勉強会 80

$a2

0

0

1

0

0

0

0

1

やばい奴ら

循環参照の GC - MarkGray

今の状態◦ 候補から到達できるオブジェクトは灰色

◦ 灰色以外からの参照のみカウント

2015/02/27 第87回 PHP 勉強会 81

$a2

0

0

1

0

0

0

0

1

やばい奴ら

循環参照の GC - Scan

矢印を辿りながら◦ 参照カウントが 0 なら「白」にする

2015/02/27 第87回 PHP 勉強会 82

$a2

0

0

1

0

0

0

0

1

やばい奴ら

循環参照の GC - Scan

矢印を辿りながら◦ 参照カウントが 0 なら「白」にする

2015/02/27 第87回 PHP 勉強会 83

$a2

0

0

1

0

0

0

0

1

やばい奴ら

循環参照の GC - Scan

矢印を辿りながら◦ 参照カウントが 0 なら「白」にする

2015/02/27 第87回 PHP 勉強会 84

$a2

0

0

1

0

0

0

0

1

やばい奴ら

循環参照の GC - Scan

矢印を辿りながら◦ 参照カウントが 0 なら「白」にする

2015/02/27 第87回 PHP 勉強会 85

$a2

0

0

1

0

0

0

0

1

やばい奴ら

循環参照の GC - Scan

矢印を辿りながら◦ 参照カウントが 0 なら「白」にする

◦ 1 以上なら「黒」にして・・・

2015/02/27 第87回 PHP 勉強会 86

$a2

0

0

1

0

0

0

0

1

やばい奴ら

循環参照の GC - ScanBlack

矢印を辿りながら◦ 参照カウントが 0 なら「白」にする

◦ 1 以上なら「黒」にして・・・◦ 減らしてしまった参照カウントを戻していく

2015/02/27 第87回 PHP 勉強会 87

$a2

0

0

1

0

0

0

1

1

やばい奴ら

循環参照の GC - ScanBlack

矢印を辿りながら◦ 参照カウントが 0 なら「白」にする

◦ 1 以上なら「黒」にして・・・◦ 減らしてしまった参照カウントを戻していく

2015/02/27 第87回 PHP 勉強会 88

$a2

0

0

1

0

0

1

1

1

やばい奴ら

循環参照の GC - ScanBlack

矢印を辿りながら◦ 参照カウントが 0 なら「白」にする

◦ 1 以上なら「黒」にして・・・◦ 減らしてしまった参照カウントを戻していく

2015/02/27 第87回 PHP 勉強会 89

$a2

0

0

1

0

0

1

2

1

やばい奴ら

循環参照の GC - ScanBlack

矢印を辿りながら◦ 参照カウントが 0 なら「白」にする

◦ 1 以上なら「黒」にして・・・◦ 減らしてしまった参照カウントを戻していく

2015/02/27 第87回 PHP 勉強会 90

$a2

0

0

1

0

0

1

2

2

やばい奴ら

循環参照の GC - Scan

矢印を辿りながら◦ 参照カウントが 0 なら「白」にする

◦ 1 以上なら「黒」にして・・・◦ 減らしてしまった参照カウントを戻していく

2015/02/27 第87回 PHP 勉強会 91

$a2

0

0

1

0

0

1

2

2

やばい奴ら

循環参照の GC - Scan

矢印を辿りながら◦ 参照カウントが 0 なら「白」にする

◦ 1 以上なら「黒」にして・・・◦ 減らしてしまった参照カウントを戻していく

2015/02/27 第87回 PHP 勉強会 92

$a2

0

0

1

0

0

1

2

2

やばい奴ら

循環参照の GC - Scan

矢印を辿りながら◦ 参照カウントが 0 なら「白」にする

◦ 1 以上なら「黒」にして・・・◦ 減らしてしまった参照カウントを戻していく

2015/02/27 第87回 PHP 勉強会 93

$a2

0

0

1

0

0

1

2

2

やばい奴ら

循環参照の GC - Scan

矢印を辿りながら◦ 参照カウントが 0 なら「白」にする

◦ 1 以上なら「黒」にして・・・◦ 減らしてしまった参照カウントを戻していく

2015/02/27 第87回 PHP 勉強会 94

$a2

0

0

1

0

0

1

2

2

やばい奴ら

循環参照の GC - Scan

矢印を辿りながら◦ 参照カウントが 0 なら「白」にする

◦ 1 以上なら「黒」にして・・・◦ 減らしてしまった参照カウントを戻していく

2015/02/27 第87回 PHP 勉強会 95

$a2

0

0

1

0

0

1

2

2

やばい奴ら

循環参照の GC - Scan

今の状態◦ 到達できるオブジェクトは黒

◦ 到達できないオブジェクトは白

2015/02/27 第87回 PHP 勉強会 96

$a2

0

0

1

0

0

1

2

2

やばい奴ら

循環参照の GC - CollectWhite

矢印を辿りながら◦ 「白」のオブジェクトを回収する

2015/02/27 第87回 PHP 勉強会 97

$a2

0

0

1

0

0

1

2

2

やばい奴ら

循環参照の GC - CollectWhite

矢印を辿りながら◦ 「白」のオブジェクトを回収する

2015/02/27 第87回 PHP 勉強会 98

$a2

0

0

1

0

0

1

2

2

やばい奴ら

循環参照の GC - CollectWhite

矢印を辿りながら◦ 「白」のオブジェクトを回収する

2015/02/27 第87回 PHP 勉強会 99

$a2

0

0

1

0

0

1

2

2

やばい奴ら

循環参照の GC - CollectWhite

矢印を辿りながら◦ 「白」のオブジェクトを回収する

2015/02/27 第87回 PHP 勉強会 100

$a2

0

0

1

0

0

1

2

2

やばい奴ら

循環参照の GC - CollectWhite

矢印を辿りながら◦ 「白」のオブジェクトを回収する

2015/02/27 第87回 PHP 勉強会 101

$a2

0

0

1

0

0

1

2

2

やばい奴ら

循環参照の GC - CollectWhite

矢印を辿りながら◦ 「白」のオブジェクトを回収する

2015/02/27 第87回 PHP 勉強会 102

$a2

0

0

1

0

0

1

2

2

やばい奴ら

循環参照の GC - CollectWhite

矢印を辿りながら◦ 「白」のオブジェクトを回収する

2015/02/27 第87回 PHP 勉強会 103

$a2

0

1

0

0

1

2

2

やばい奴ら

循環参照の GC - CollectWhite

矢印を辿りながら◦ 「白」のオブジェクトを回収する

2015/02/27 第87回 PHP 勉強会 104

$a2

0

1

0 1

2

2

やばい奴ら

循環参照の GC - CollectWhite

矢印を辿りながら◦ 「白」のオブジェクトを回収する

2015/02/27 第87回 PHP 勉強会 105

$a2

0

1

1

2

2

やばい奴ら

循環参照の GC - CollectWhite

矢印を辿りながら◦ 「白」のオブジェクトを回収する

2015/02/27 第87回 PHP 勉強会 106

$a2

0

1

1

2

2

やばい奴ら

循環参照の GC - CollectWhite

矢印を辿りながら◦ 「白」のオブジェクトを回収する

2015/02/27 第87回 PHP 勉強会 107

$a2 1

1

2

2

やばい奴ら

循環参照の GC - CollectWhite

今の状態◦ 到達できるオブジェクトのみ残っている

2015/02/27 第87回 PHP 勉強会 108

$a2 1

1

2

2

やばい奴ら

gc_disable() の話

2015/02/27 第87回 PHP 勉強会 109

循環参照の GC (再考)最初の状態が以下だったとしたら・・・

2015/02/27 第87回 PHP 勉強会 110

1$a1

$a2

2

3

1

1

1

2

2

2

循環参照の GC - Release

参照カウントが 0 になった場合◦ ゴミなので回収する(通常の参照カウント方式)

2015/02/27 第87回 PHP 勉強会 111

unset($a1);

0

$a2

2

3

1

1

1

2

2

2

循環参照の GC - PossibleRoot

参照カウントが減ったがまだ 0 ではない場合◦ ゴミができてしまった「かもしれない」

◦ 候補として覚えておく

2015/02/27 第87回 PHP 勉強会 112

$a2

1

3

1

1

1

2

2

2

やばい奴ら

循環参照の GC - MarkRoots

候補のオブジェクトを「灰色」にする

2015/02/27 第87回 PHP 勉強会 113

$a2

1

3

1

1

1

2

2

2

やばい奴ら

循環参照の GC - MarkGray

矢印を辿りながら◦ 参照カウントを 1 減らす

◦ 辿ったオブジェクトを「灰色」にする

2015/02/27 第87回 PHP 勉強会 114

$a2

1

3

1

0

1

2

2

2

やばい奴ら

循環参照の GC - MarkGray

矢印を辿りながら◦ 参照カウントを 1 減らす

◦ 辿ったオブジェクトを「灰色」にする

2015/02/27 第87回 PHP 勉強会 115

$a2

1

3

1

0

1

1

2

2

やばい奴ら

循環参照の GC - MarkGray

矢印を辿りながら◦ 参照カウントを 1 減らす

◦ 辿ったオブジェクトを「灰色」にする

2015/02/27 第87回 PHP 勉強会 116

$a2

1

3

1

0

1

1

1

2

やばい奴ら

循環参照の GC - MarkGray

矢印を辿りながら◦ 参照カウントを 1 減らす

◦ 辿ったオブジェクトを「灰色」にする

2015/02/27 第87回 PHP 勉強会 117

$a2

1

3

1

0

1

0

1

2

やばい奴ら

循環参照の GC - MarkGray

矢印を辿りながら◦ 参照カウントを 1 減らす

◦ 辿ったオブジェクトを「灰色」にする

2015/02/27 第87回 PHP 勉強会 118

$a2

1

3

1

0

1

0

1

1

やばい奴ら

循環参照の GC - MarkGray

矢印を辿りながら◦ 参照カウントを 1 減らす

◦ 辿ったオブジェクトを「灰色」にする

2015/02/27 第87回 PHP 勉強会 119

$a2

1

3

1

0

1

0

0

1

やばい奴ら

循環参照の GC - MarkGray

矢印を辿りながら◦ 参照カウントを 1 減らす

◦ 辿ったオブジェクトを「灰色」にする

2015/02/27 第87回 PHP 勉強会 120

$a2

1

3

1

0

0

0

0

1

やばい奴ら

循環参照の GC - MarkGray

矢印を辿りながら◦ 参照カウントを 1 減らす

◦ 辿ったオブジェクトを「灰色」にする

2015/02/27 第87回 PHP 勉強会 121

$a2

1

2

1

0

0

0

0

1

やばい奴ら

循環参照の GC - MarkGray

矢印を辿りながら◦ 参照カウントを 1 減らす

◦ 辿ったオブジェクトを「灰色」にする

2015/02/27 第87回 PHP 勉強会 122

$a2

0

2

1

0

0

0

0

1

やばい奴ら

循環参照の GC - MarkGray

矢印を辿りながら◦ 参照カウントを 1 減らす

◦ 辿ったオブジェクトを「灰色」にする

2015/02/27 第87回 PHP 勉強会 123

$a2

0

1

1

0

0

0

0

1

やばい奴ら

循環参照の GC - MarkGray

今の状態◦ 候補から到達できるオブジェクトは灰色

◦ 灰色以外からの参照のみカウント

2015/02/27 第87回 PHP 勉強会 124

$a2

0

1

1

0

0

0

0

1

やばい奴ら

循環参照の GC - Scan

矢印を辿りながら◦ 参照カウントが 0 なら「白」にする

2015/02/27 第87回 PHP 勉強会 125

$a2

0

1

1

0

0

0

0

1

やばい奴ら

循環参照の GC - Scan

矢印を辿りながら◦ 参照カウントが 0 なら「白」にする

2015/02/27 第87回 PHP 勉強会 126

$a2

0

1

1

0

0

0

0

1

やばい奴ら

循環参照の GC - Scan

矢印を辿りながら◦ 参照カウントが 0 なら「白」にする

2015/02/27 第87回 PHP 勉強会 127

$a2

0

1

1

0

0

0

0

1

やばい奴ら

循環参照の GC - Scan

矢印を辿りながら◦ 参照カウントが 0 なら「白」にする

2015/02/27 第87回 PHP 勉強会 128

$a2

0

1

1

0

0

0

0

1

やばい奴ら

循環参照の GC - Scan

矢印を辿りながら◦ 参照カウントが 0 なら「白」にする

◦ 1 以上なら「黒」にして・・・

2015/02/27 第87回 PHP 勉強会 129

$a2

0

1

1

0

0

0

0

1

やばい奴ら

循環参照の GC - ScanBlack

矢印を辿りながら◦ 参照カウントが 0 なら「白」にする

◦ 1 以上なら「黒」にして・・・◦ 減らしてしまった参照カウントを戻していく

2015/02/27 第87回 PHP 勉強会 130

$a2

0

1

1

0

0

0

1

1

やばい奴ら

循環参照の GC - ScanBlack

矢印を辿りながら◦ 参照カウントが 0 なら「白」にする

◦ 1 以上なら「黒」にして・・・◦ 減らしてしまった参照カウントを戻していく

2015/02/27 第87回 PHP 勉強会 131

$a2

0

1

1

0

0

1

1

1

やばい奴ら

循環参照の GC - ScanBlack

矢印を辿りながら◦ 参照カウントが 0 なら「白」にする

◦ 1 以上なら「黒」にして・・・◦ 減らしてしまった参照カウントを戻していく

2015/02/27 第87回 PHP 勉強会 132

$a2

0

1

1

0

0

1

2

1

やばい奴ら

循環参照の GC - ScanBlack

矢印を辿りながら◦ 参照カウントが 0 なら「白」にする

◦ 1 以上なら「黒」にして・・・◦ 減らしてしまった参照カウントを戻していく

2015/02/27 第87回 PHP 勉強会 133

$a2

0

1

1

0

0

1

2

2

やばい奴ら

循環参照の GC - Scan

矢印を辿りながら◦ 参照カウントが 0 なら「白」にする

◦ 1 以上なら「黒」にして・・・◦ 減らしてしまった参照カウントを戻していく

2015/02/27 第87回 PHP 勉強会 134

$a2

0

1

1

0

0

1

2

2

やばい奴ら

循環参照の GC - Scan

矢印を辿りながら◦ 参照カウントが 0 なら「白」にする

◦ 1 以上なら「黒」にして・・・◦ 減らしてしまった参照カウントを戻していく

2015/02/27 第87回 PHP 勉強会 135

$a2

0

1

1

0

0

1

2

2

やばい奴ら

循環参照の GC - Scan

矢印を辿りながら◦ 参照カウントが 0 なら「白」にする

◦ 1 以上なら「黒」にして・・・◦ 減らしてしまった参照カウントを戻していく

2015/02/27 第87回 PHP 勉強会 136

$a2

0

1

1

0

0

1

2

2

やばい奴ら

循環参照の GC - ScanBlack

矢印を辿りながら◦ 参照カウントが 0 なら「白」にする

◦ 1 以上なら「黒」にして・・・◦ 減らしてしまった参照カウントを戻していく

2015/02/27 第87回 PHP 勉強会 137

$a2

1

1

1

0

0

1

2

2

やばい奴ら

循環参照の GC - ScanBlack

矢印を辿りながら◦ 参照カウントが 0 なら「白」にする

◦ 1 以上なら「黒」にして・・・◦ 減らしてしまった参照カウントを戻していく

2015/02/27 第87回 PHP 勉強会 138

$a2

1

1

1

1

0

1

2

2

やばい奴ら

循環参照の GC - ScanBlack

矢印を辿りながら◦ 参照カウントが 0 なら「白」にする

◦ 1 以上なら「黒」にして・・・◦ 減らしてしまった参照カウントを戻していく

2015/02/27 第87回 PHP 勉強会 139

$a2

1

1

1

1

0

2

2

2

やばい奴ら

循環参照の GC - ScanBlack

矢印を辿りながら◦ 参照カウントが 0 なら「白」にする

◦ 1 以上なら「黒」にして・・・◦ 減らしてしまった参照カウントを戻していく

2015/02/27 第87回 PHP 勉強会 140

$a2

1

1

1

1

1

2

2

2

やばい奴ら

循環参照の GC - ScanBlack

矢印を辿りながら◦ 参照カウントが 0 なら「白」にする

◦ 1 以上なら「黒」にして・・・◦ 減らしてしまった参照カウントを戻していく

2015/02/27 第87回 PHP 勉強会 141

$a2

1

2

1

1

1

2

2

2

やばい奴ら

循環参照の GC - ScanBlack

矢印を辿りながら◦ 参照カウントが 0 なら「白」にする

◦ 1 以上なら「黒」にして・・・◦ 減らしてしまった参照カウントを戻していく

2015/02/27 第87回 PHP 勉強会 142

$a2

1

3

1

1

1

2

2

2

やばい奴ら

循環参照の GC - Scan

矢印を辿りながら◦ 参照カウントが 0 なら「白」にする

◦ 1 以上なら「黒」にして・・・◦ 減らしてしまった参照カウントを戻していく

2015/02/27 第87回 PHP 勉強会 143

$a2

1

3

1

1

1

2

2

2

やばい奴ら

循環参照の GCゴミなど一つも無かった◦ 時間の無駄

2015/02/27 第87回 PHP 勉強会 144

$a2

1

3

1

1

1

2

2

2

やばい奴ら

ところで

2015/02/27 第87回 PHP 勉強会 145

ゴミの候補はいつできる?関数を呼ぶだけでゴミの候補が増える (引数の型による)

2015/02/27 第87回 PHP 勉強会 146

<?php$a = new MyList();

function doSomething($foo) {}

doSomething($a);

ゴミの候補はいつできる?関数を呼ぶだけでゴミの候補が増える (引数の型による)

2015/02/27 第87回 PHP 勉強会 147

<?php$a = new MyList();

function doSomething($foo) {}

doSomething($a);

$a 1

◦ doSomething実行前

ゴミの候補はいつできる?関数を呼ぶだけでゴミの候補が増える (引数の型による)

2015/02/27 第87回 PHP 勉強会 148

<?php$a = new MyList();

function doSomething($foo) {}

doSomething($a);

$a 2

$foo

◦ doSomething実行中

ゴミの候補はいつできる?関数を呼ぶだけでゴミの候補が増える (引数の型による)

2015/02/27 第87回 PHP 勉強会 149

<?php$a = new MyList();

function doSomething($foo) {}

doSomething($a);

$a 1

◦ doSomething実行後

gc_disable() の使いどころ原則◦ 普通は gc_disable() なんて考えなくてよい

◦ メモリリークの元

次のようなプログラムは検討の余地あり◦ 巨大なグラフ (or 木, リスト, ...) を辿りながら処理する

◦ そのグラフは循環参照によるゴミを出さない

2015/02/27 第87回 PHP 勉強会 150

実験こんなデータ構造を作って各要素を引数に関数を呼ぶ

2015/02/27 第87回 PHP 勉強会 151

1

・・・

1

1

・・・

1

1

1

・・・

・・・

配列

リスト

実験こんなデータ構造を作って各要素を引数に関数を呼ぶ

2015/02/27 第87回 PHP 勉強会 152

1

・・・

1

1

・・・

1

1

1

・・・

・・・

配列

リスト

配列の要素数によって循環参照の GC が発生したり発生しなかったりする

実験プログラム (データ構造を組み立てる部分は省略)

2015/02/27 第87回 PHP 勉強会 153

...gc_collect_cycles();

$start = microtime(true);for ($i = 0; $i < 10; ++$i) {

foreach ($arrayOfList as $list) {doSomething($list); // doSomething は空の関数

}}$end = microtime(true);

◦ $arrayOfListの要素数を変更しながら ($end - $start) を計測

◦ $list の長さは固定 (100 とした)

実験結果

2015/02/27 第87回 PHP 勉強会 154

PHP 5.6.5 との比較memory_limit=1024M として実験

Core i5-3337U 1.80GHz

実験結果

2015/02/27 第87回 PHP 勉強会 155

PHP 7.0.0 との比較memory_limit=1024M として実験

Core i5-3337U 1.80GHz

おわりありがとうございました

2015/02/27 第87回 PHP 勉強会 156