Search Unity

Trying to understand a memory leak with nativearray and raycastcommand

Discussion in 'Editor & General Support' started by lmbarns, Jan 18, 2020.

  1. lmbarns

    lmbarns

    Joined:
    Jul 14, 2011
    Posts:
    1,628
    I assume I just can't do this, but wanted to verify it's not something I can fix, because it works most of the time, but also throws errors periodically.

    After performing a batch of raycasts, I try to use parallel linq to iterate over them and it often works, but kicks off a bunch of warnings about memory leaks AFTER it's run:

    Unity 2019.2.6f1
    I enabled full stack trace, but not sure what's wrong.

    Warnings:
    After it runs a bunch of times, it starts throwing:
    Error:
    Code (CSharp):
    1. InvalidOperationException: You are not allowed to access a NativeArray outside the main thread and job threads.
    2. Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.CheckReadAndThrowNoEarlyOut (Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle handle) <0x1960f774590 + 0x00052> in <e3232360d51c46c786dd547e2f0b3f8b>:0
    3. Unity.Collections.NativeSlice`1[T].CheckReadIndex (System.Int32 index) (at C:/buildslave/unity/build/Runtime/Export/NativeArray/NativeSlice.cs:179)
    4. Unity.Collections.NativeSlice`1[T].get_Item (System.Int32 index) (at C:/buildslave/unity/build/Runtime/Export/NativeArray/NativeSlice.cs:200)
    5. Unity.Collections.NativeSlice`1+Enumerator[T].get_Current () <0x1960f773b00 + 0x000ba> in <e3232360d51c46c786dd547e2f0b3f8b>:0
    6. System.Linq.Parallel.PartitionedDataSource`1+ContiguousChunkLazyEnumerator[T].MoveNext (T& currentElement, System.Int32& currentKey) (at <fbb5ed17eb6e46c680000f8910ebb50c>:0)
    7. System.Linq.Parallel.WhereQueryOperator`1+WhereQueryOperatorEnumerator`1[TInputOutput,TKey].MoveNext (TInputOutput& currentElement, TKey& currentKey) (at <fbb5ed17eb6e46c680000f8910ebb50c>:0)
    8. System.Linq.Parallel.ForAllOperator`1+ForAllEnumerator`1[TInput,TKey].MoveNext (TInput& currentElement, System.Int32& currentKey) (at <fbb5ed17eb6e46c680000f8910ebb50c>:0)
    9. System.Linq.Parallel.ForAllSpoolingTask`2[TInputOutput,TIgnoreKey].SpoolingWork () (at <fbb5ed17eb6e46c680000f8910ebb50c>:0)
    Code (CSharp):
    1. void ProcessRaycasts(Ray[] rays)
    2.     {
    3.         var results = new NativeArray<RaycastHit>(rays.Length, Allocator.TempJob);
    4.         var commands = new NativeArray<RaycastCommand>(rays.Length, Allocator.TempJob);
    5.  
    6.         for (int i = 0, b = rays.Length; i < b; i++)
    7.         {
    8.             commands[i] = new RaycastCommand(rays[i].origin, rays[i].direction);
    9.         }
    10.         // Schedule the batch of raycasts
    11.         JobHandle handle = RaycastCommand.ScheduleBatch(commands, results, 1, default(JobHandle));
    12.  
    13.         // Wait for the batch processing job to complete
    14.         handle.Complete();
    15.              
    16.         //Sizes must match for Slice to work.      
    17.         if (Marshal.SizeOf(typeof(HitInfo)) != Marshal.SizeOf(typeof(RaycastHit)))
    18.         {
    19.             Debug.Log("Not Equal: " + Marshal.SizeOf(typeof(HitInfo)) + " : " + Marshal.SizeOf(typeof(RaycastHit)));
    20.             throw new Exception("Sizes don't match");
    21.         }
    22.      
    23.         //Convert RaycastHit to HitInfo to attempt using in parallel
    24.         var data = results.Slice(0, results.Length).SliceConvert<HitInfo>();
    25.  
    26.  
    27.         /******************************************************************************/
    28.  
    29.         var parallelQuery = from num in data.AsParallel()
    30.                             where num.m_Collider > 0
    31.                             select num;        //Run query
    32.  
    33.  
    34.         parallelQuery.ForAll((e) => {
    35.             if (Hits.TryAdd(m_ColliderMap[e.m_Collider], e))
    36.             {
    37.                 Debug.Log("Success adding hit ");
    38.             } else
    39.             {
    40.                 Debug.Log("Failed: Already in array");
    41.             }
    42.         });
    43.         /****************************************************************************/
    44.  
    45.      
    46.         // Dispose the buffers
    47.         results.Dispose();
    48.         commands.Dispose();
    49.     }
    Sample Scene and script setup, just play, click the mouse and look at log:

    I'm wondering if it's the Slice that's not getting cleaned up? Or is this a case of "not supposed to do that", or just a bug?
     

    Attached Files:

    Last edited: Jan 18, 2020