Search Unity

Why is the single-hit variant of Physics.Raycast generating garbage?

Discussion in 'Physics' started by country_dragon, Nov 12, 2017.

  1. country_dragon

    country_dragon

    Joined:
    Jun 26, 2014
    Posts:
    7
    Hi

    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.
     
    stonstad likes this.
  2. nat42

    nat42

    Joined:
    Jun 10, 2017
    Posts:
    353
    RaycastHit looks to be an output param with a decent set of properties?
     
  3. country_dragon

    country_dragon

    Joined:
    Jun 26, 2014
    Posts:
    7
    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.
     
  4. Sluggy

    Sluggy

    Joined:
    Nov 27, 2012
    Posts:
    983
    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.
     
  5. HiddenMonk

    HiddenMonk

    Joined:
    Dec 19, 2014
    Posts:
    987
    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.
    Code (CSharp):
    1.  
    2. public class TestRaycastGarbage : MonoBehaviour
    3. {
    4.     public float castDistance = Mathf.Infinity;
    5.     public LayerMask layerMask = Physics.AllLayers;
    6.     public int loopCount = 1000;
    7.  
    8.     void Update()
    9.     {
    10.         for(int i = 0; i < loopCount; i++)
    11.         {
    12.             RaycastHit hitInfo;
    13.             Ray ray = new Ray(transform.position, transform.forward);
    14.             Physics.Raycast(ray, out hitInfo, castDistance, layerMask, QueryTriggerInteraction.UseGlobal);
    15.         }
    16.     }
    17. }
    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.
     
    WendelinReich likes this.
  6. stonstad

    stonstad

    Joined:
    Jan 19, 2018
    Posts:
    659
    * 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.
     
    Last edited: Jan 16, 2020
  7. stonstad

    stonstad

    Joined:
    Jan 19, 2018
    Posts:
    659
    * 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.
     
    Last edited: Jan 16, 2020
  8. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    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.
     
    stonstad likes this.
  9. stonstad

    stonstad

    Joined:
    Jan 19, 2018
    Posts:
    659
    @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!
     
    hippocoder likes this.
  10. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Great!

    Don't forget though editor often allocates where runtime doesn't, for various debuggery and inspector stuff.