Does anybody know why the single-hit variant of Physics.Raycast appears to sometimes generate 40 bytes of garbage?
i.e. this version:
public static bool Raycast (Ray ray, out RaycastHit hitInfo, float maxDistance, int layerMask, QueryTriggerInteraction queryTriggerInteraction);
I can see why the multi-hit variant would produce garbage, because it needs to allocate an array of hit results (unless using Physics.RaycastNonAlloc of course). However, this version only requires value type parameters so no allocations should be required.
Thanks
PS: I’m currently on Unity version 5.5.4f1 as I don’t want to upgrade at the moment.
Yeah, the RaycastHit output is fine - it’s functioning correctly and returning the expected result but I really don’t see why this function should produce garbage. I can only assume that it’s internally calling Physics.RaycastAll and then returning the first result, which seems wasteful.
I’ve now created my own wrapper function that calls Physics.RaycastNonAlloc using a static buffer of hit results and then I just return the first entry. This fixes the garbage issue but this kind of optimisation really should be done in the engine.
RaycastHit is used as an out parameter, which means it must be assigned a value from within the function. As well, RaycastHit info is (mostly) immutable which means you can’t simply assign values to existing fields but rather, must allocate a new instance of a RaycastHit struct when you want to change the data.
Also, for the most part, the Non-NonAlloc methods are legacy code that is left in for compatibility and convenience but Unity doesn’t recommend using.
On a slightly offtopic comment, some folks seem to think that a generational GC would make no difference for day-to-day tasks of a game programmer because ‘You must always be aware of your allocations’ and such. However, this is exactly the sort of problem that would simply disappear if such a GC existed.
I did a test in Unity 2017.1.0p4 and I dont see any garbage being generated with the code below while having 5 cubes in front of the cast. Cant say for your version, but maybe make a new scene and test the code below.
public class TestRaycastGarbage : MonoBehaviour
{
public float castDistance = Mathf.Infinity;
public LayerMask layerMask = Physics.AllLayers;
public int loopCount = 1000;
void Update()
{
for(int i = 0; i < loopCount; i++)
{
RaycastHit hitInfo;
Ray ray = new Ray(transform.position, transform.forward);
Physics.Raycast(ray, out hitInfo, castDistance, layerMask, QueryTriggerInteraction.UseGlobal);
}
}
}
Unity RaycastAll doc (which RaycastAllNonAloc doc says its like RaycastAll) warns that the order is not guaranteed, so just because its the first entry does not mean its the first hit.
updated – one of my parameters to the function was allocating. Physics.Raycast does not allocate for me.
Hi country_dragon. I just wanted to reach out and say that I appreciate your post and question. I just ran into the same behavior today and asked myself the same question – why would a non-collection creating function generate garbage. Most of the documentation I have seen indicates that Physics.RaycastAll should generate garbage and Physics.Raycast should not. … but it can and does. Thank you for your post.
updated – one of my parameters to the function was allocating. Physics.Raycast does not allocate for me.
Raycast hit itself is a struct (non-GC allocating). But within it maintains class/heap references to a collider and transforms. Since those references point to existing allocated memory, I certainly fail to see why RaycastHit should generate any garbage. Best explanation is the concept presented here that it does so due to poor legacy design.
Test if it allocates in a build because the editor often frequently does allocations for many Unity functions and features where the game does not.
Also, you can of course use non alloc variants for 1 ray if you’re not sure. Personally, I am not recording GC allocs with the standard Raycast command.
@hoppocoder THANK YOU! Your confirmation of no leak prompted me to really take a critical look at this code. I had a parameter which converted an array to a bit mask, and this code used a function with Fn(params int[ ]). I missed it! Physics.Raycast is not allocating. Thank you!