File tree 4 files changed +184
-1
lines changed
4 files changed +184
-1
lines changed Original file line number Diff line number Diff line change
1
+ --TEST--
2
+ GH-13670 001
3
+ --FILE--
4
+ <?php
5
+
6
+ register_shutdown_function (function () {
7
+ global $ shutdown ;
8
+ $ shutdown = true ;
9
+ });
10
+
11
+ class Cycle {
12
+ public $ self ;
13
+ public function __construct () {
14
+ $ this ->self = $ this ;
15
+ }
16
+ public function __destruct () {
17
+ global $ shutdown ;
18
+ if (!$ shutdown ) {
19
+ new Cycle ();
20
+ }
21
+ }
22
+ }
23
+
24
+ $ defaultThreshold = gc_status ()['threshold ' ];
25
+ for ($ i = 0 ; $ i < $ defaultThreshold +1 ; $ i ++) {
26
+ new Cycle ();
27
+ }
28
+
29
+ $ objs = [];
30
+ for ($ i = 0 ; $ i < 100 ; $ i ++) {
31
+ $ obj = new stdClass ;
32
+ $ objs [] = $ obj ;
33
+ }
34
+
35
+ $ st = gc_status ();
36
+
37
+ if ($ st ['runs ' ] > 10 ) {
38
+ var_dump ($ st );
39
+ }
40
+ ?>
41
+ ==DONE==
42
+ --EXPECT--
43
+ ==DONE==
Original file line number Diff line number Diff line change
1
+ --TEST--
2
+ GH-13670 002
3
+ --FILE--
4
+ <?php
5
+
6
+ register_shutdown_function (function () {
7
+ global $ shutdown ;
8
+ $ shutdown = true ;
9
+ });
10
+
11
+ class Cycle {
12
+ public $ self ;
13
+ public function __construct () {
14
+ $ this ->self = $ this ;
15
+ }
16
+ }
17
+
18
+ class Canary {
19
+ public $ self ;
20
+ public function __construct () {
21
+ $ this ->self = $ this ;
22
+ }
23
+ public function __destruct () {
24
+ global $ shutdown ;
25
+ if (!$ shutdown ) {
26
+ work ();
27
+ }
28
+ }
29
+ }
30
+
31
+ function work () {
32
+ global $ objs , $ defaultThreshold ;
33
+ new Canary ();
34
+ // Create some collectable garbage so the next run will not adjust
35
+ // threshold
36
+ for ($ i = 0 ; $ i < 100 ; $ i ++) {
37
+ new Cycle ();
38
+ }
39
+ // Add potential garbage to buffer
40
+ foreach (array_slice ($ objs , 0 , $ defaultThreshold ) as $ obj ) {
41
+ $ o = $ obj ;
42
+ }
43
+ }
44
+
45
+ $ defaultThreshold = gc_status ()['threshold ' ];
46
+ $ objs = [];
47
+ for ($ i = 0 ; $ i < $ defaultThreshold *2 ; $ i ++) {
48
+ $ obj = new stdClass ;
49
+ $ objs [] = $ obj ;
50
+ }
51
+
52
+ work ();
53
+
54
+ foreach ($ objs as $ obj ) {
55
+ $ o = $ obj ;
56
+ }
57
+
58
+ $ st = gc_status ();
59
+
60
+ if ($ st ['runs ' ] > 10 ) {
61
+ var_dump ($ st );
62
+ }
63
+ ?>
64
+ ==DONE==
65
+ --EXPECT--
66
+ ==DONE==
Original file line number Diff line number Diff line change
1
+ --TEST--
2
+ GH-13670 003
3
+ --FILE--
4
+ <?php
5
+
6
+ register_shutdown_function (function () {
7
+ global $ shutdown ;
8
+ $ shutdown = true ;
9
+ });
10
+
11
+ class Cycle {
12
+ public $ self ;
13
+ public function __construct () {
14
+ $ this ->self = $ this ;
15
+ }
16
+ }
17
+
18
+ class Canary {
19
+ public $ self ;
20
+ public function __construct () {
21
+ $ this ->self = $ this ;
22
+ }
23
+ public function __destruct () {
24
+ global $ shutdown ;
25
+ if (!$ shutdown ) {
26
+ work ();
27
+ }
28
+ }
29
+ }
30
+
31
+ function work () {
32
+ global $ objs , $ defaultThreshold ;
33
+ new Canary ();
34
+ // Create some collectable garbage so the next run will not adjust
35
+ // threshold
36
+ for ($ i = 0 ; $ i < 100 ; $ i ++) {
37
+ new Cycle ();
38
+ }
39
+ // Add potential garbage to buffer
40
+ foreach (array_slice ($ objs , 0 , $ defaultThreshold ) as $ obj ) {
41
+ $ o = $ obj ;
42
+ }
43
+ }
44
+
45
+ $ defaultThreshold = gc_status ()['threshold ' ];
46
+ $ objs = [];
47
+ for ($ i = 0 ; $ i < $ defaultThreshold *2 ; $ i ++) {
48
+ $ obj = new stdClass ;
49
+ $ objs [] = $ obj ;
50
+ }
51
+
52
+ work ();
53
+
54
+ // Result of array_slice() is a tmpvar that will be checked by
55
+ // zend_gc_check_root_tmpvars()
56
+ foreach (array_slice ($ objs , -10 ) as $ obj ) {
57
+ $ o = $ obj ;
58
+ }
59
+
60
+ $ st = gc_status ();
61
+
62
+ if ($ st ['runs ' ] > 10 ) {
63
+ var_dump ($ st );
64
+ }
65
+ ?>
66
+ ==DONE==
67
+ --EXPECT--
68
+ ==DONE==
Original file line number Diff line number Diff line change @@ -608,7 +608,7 @@ static void gc_adjust_threshold(int count)
608
608
/* TODO Very simple heuristic for dynamic GC buffer resizing:
609
609
* If there are "too few" collections, increase the collection threshold
610
610
* by a fixed step */
611
- if (count < GC_THRESHOLD_TRIGGER ) {
611
+ if (count < GC_THRESHOLD_TRIGGER || GC_G ( num_roots ) >= GC_G ( gc_threshold ) ) {
612
612
/* increase */
613
613
if (GC_G (gc_threshold ) < GC_THRESHOLD_MAX ) {
614
614
new_threshold = GC_G (gc_threshold ) + GC_THRESHOLD_STEP ;
@@ -1990,7 +1990,13 @@ ZEND_API int zend_gc_collect_cycles(void)
1990
1990
1991
1991
finish :
1992
1992
zend_get_gc_buffer_release ();
1993
+
1994
+ /* Prevent GC from running during zend_gc_check_root_tmpvars, before
1995
+ * gc_threshold is adjusted, as this may result in unbounded recursion */
1996
+ GC_G (gc_active ) = 1 ;
1993
1997
zend_gc_check_root_tmpvars ();
1998
+ GC_G (gc_active ) = 0 ;
1999
+
1994
2000
GC_G (collector_time ) += zend_hrtime () - start_time ;
1995
2001
return total_count ;
1996
2002
}
You can’t perform that action at this time.
0 commit comments