-
Notifications
You must be signed in to change notification settings - Fork 7.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Objects which can't possibly be GC roots take up slots in GC root buffer #17127
Comments
Related. #9979. As mentioned in that PR, once PHP 9 inhibits the addition of dynamic objects, it becomes possible to not to objects with exclusively non-recursively typed properties to the GC buffer. It might also be possible to achieve something similar by appending such objects to the buffer only once any dynamic properties are added to them. Another note on the PR above: After some time I realized the approach is unsound. The engine adds objects to the buffer on DELREF under the assumption that one of the nodes in the graph is eventually no longer referenced from the outside world (e.g. stack, static var, etc.). Selectively excluding nodes from the buffer is problematic then when they are the actual root nodes, i.e. the ones originally referenced from the outside, as they are the only ones guaranteed to be DELREFed. Anyway, not too relevant for this particular issue. |
Not quite sure I understand why typed properties are important. Isn't it possible to just set a flag on the object during write_property if the written zval may have cycles? |
@dktapps Yes, but writing to objects without releasing them is also very common, so it might actually achieve the opposite effect, we don't want to handle this logic in fast paths. |
Quick test on internal extensions:
Each I'll check Symfony Demo now. |
Also worth mentioning: Line 631 in 07cd468
called from here: Line 664 in 07cd468
However this will have a performance impact for code where acyclic objects are still flooding the buffer. In PocketMine's case in particular, a 10k GC threshold has a noticeable impact if the threshold adjustment accounts for acyclic objects. 100k works a lot better. Fixing this would probably still be a good idea just to deal with objects with acyclic dynamic properties. |
Acyclic objects don't need to be added to the GC. We know an object is acyclic if all properties are typed as acyclic, and the object does not have any dynamic properties. This is possible to track at runtime with minimal overhead. Fixes phpGH-17127
Acyclic objects don't need to be added to the GC. We know an object is acyclic if all properties are typed as acyclic, and the object does not have any dynamic properties. This is possible to track at runtime with minimal overhead. Fixes phpGH-17127
Acyclic objects don't need to be added to the GC. We know an object is acyclic if all properties are typed as acyclic, and the object does not have any dynamic properties. This is possible to track at runtime with minimal overhead. Fixes phpGH-17127
Description
This has mystified me for quite some time.
In PocketMine-MP, we process and cache many simple, acyclic objects like Vector3. When these objects are unref'd (but not destroyed, as they're cached), this causes the object to land in the GC root buffer, despite the object having 0 GC-able children. This causes a couple of problems:
Since these objects are clearly acyclic, it's just wasting CPU time.
My question in a nutshell
Is there a technical reason why objects with no collectable children are included in the GC root buffer? Any object without
array
orobject
properties should be able to be ignored, shouldn't it?Demo code
Here's a test script to demonstrate what I mean.
The
V3
class in this sample clearly cannot contain any reference cycles as it only referencesfloat
. You can see that the GC time scales according to the size of the root buffer full of these acyclic objects.Example output:
PHP Version
8.3.13
Operating System
Windows
The text was updated successfully, but these errors were encountered: