File tree Expand file tree Collapse file tree 4 files changed +184
-1
lines changed
Expand file tree Collapse file tree 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)
608608 /* TODO Very simple heuristic for dynamic GC buffer resizing:
609609 * If there are "too few" collections, increase the collection threshold
610610 * by a fixed step */
611- if (count < GC_THRESHOLD_TRIGGER ) {
611+ if (count < GC_THRESHOLD_TRIGGER || GC_G ( num_roots ) >= GC_G ( gc_threshold ) ) {
612612 /* increase */
613613 if (GC_G (gc_threshold ) < GC_THRESHOLD_MAX ) {
614614 new_threshold = GC_G (gc_threshold ) + GC_THRESHOLD_STEP ;
@@ -1990,7 +1990,13 @@ ZEND_API int zend_gc_collect_cycles(void)
19901990
19911991finish :
19921992 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 ;
19931997 zend_gc_check_root_tmpvars ();
1998+ GC_G (gc_active ) = 0 ;
1999+
19942000 GC_G (collector_time ) += zend_hrtime () - start_time ;
19952001 return total_count ;
19962002}
You can’t perform that action at this time.
0 commit comments