EventSystem's PhysicsRaycaster causes allocation every frame

Can someone else confirm this?

Just adding a Physics Raycaster component to the main camera will cause 40B of allocation every frame as a result of Physics.RaycastAll(). The 2D Graphic Raycaster doesn’t allocate, though.

At first I was thinking about using it in conjunction with the UI system to not raycast through UI elements, but isn’t there already some sort of raycasting done every frame through Monobehaviour.OnMouse_ which isn’t allocating?

So would this mean that two raycasters are firing every frame?

2 Likes

I just tested this again with Unity 5.2.0p1, and still get 40B GC allocation every frame in EventSystem.Update() with the Physics Raycaster on the main camera and the EventSystem in the scene.

Guess they don’t know about Unity - Scripting API: Physics2D.RaycastNonAlloc

However, it should be noted that the physics and graphics raycasters needs to be changed to use GetRaycastIntersection (and its variants) instead of Raycast (which doesn’t work with world-space Canvases or GameObjects getting pointer events from a perspective camera).

This still happens with Unity 2017.4.7. Did you file a bug report with Unity?

This is happening in EventSystem.cs … seems like it’s not trivial to write our own version of it due to them using RaycasterManager there. The issue is in PhysicsRaycaster but the actual method call seems to be a cached reflection method … wtf??? Physics (not physics 2D) does also have a non alloc version that could/should be used: Physics.RaycastNonAlloc. Not sure why they are not using that one :frowning:

I guess PhysicsRaycaster doesn’t know ahead of time how many hits it will get back, so it allocates the array every frame. I did file a bug and here’s the response I got from QA back in 2016:

“I’ve talked to the developers and they’ve said there isn’t anything they could do about this so I’ll have to close this case. RaycastNonAlloc uses already allocated array (which has fixed size) so the number of objects that can be hit by ray has to be known before casting a ray.”

1 Like

Wow, seriously? That is not cool.

The solution is actually very simple:

Use an array that has the maximum number of objects we expect to get and add an int with the number that is actually returned (this is usually smaller than the length of the array and can never be larger than the array length). Add another int with the total number of objects that were hit. If that number is higher than the length of the array, the caller needs to increase the array size (or at least know that its missing some objects). If it’s important that all objects are found, the caller can do another call - this does of course have a performance impact (doing two Raycasts instead of one) but it only happens sporadically and never again until the number of objects that can be hit has increased. Problem solved.

An even simpler solution: Instead of using an array, use a generic list. Problem solved.

The advantage of using a generic list is you only need to have the actual number in an int, and can simply add items to the list even if the underlying array was too small and the list implementation will handle increasing the array size without you having to worry about it. The disadvantage is that adding to the list might cause allocations at unexpected times, so that’s a tradeoff to be made. Also, RaycastNonAlloc currently only supports arrays, so that API would have to be extended a little bit and that extension would not guarantee “no allocations” (but IMHO it would be enough to write that into the method documentation).

“There isn’t anything we can do” is usually the answer that a lazy or at least not very creative developer would come up with. The beauty of software-engineering is that you have almost infinite possibilities. In this case, there are at least two obvious solutions.

Hopefully they see your post… I would’ve liked to use PhysicsRaycaster but didn’t because of the allocations.