Search Unity

Lists of Native Arrays and Disposing

Discussion in 'Burst' started by 8bitgoose, Jun 4, 2021.

  1. 8bitgoose

    8bitgoose

    Joined:
    Dec 28, 2014
    Posts:
    448
    So I've got an interesting result.

    First I copy a native array over. It's my understanding that calling new NativeArray will create a deep copy of the Native Array instead of copying the reference.

    Code (CSharp):
    1. for(int i = 0, l = successList.Count; i < l; i++)
    2. {
    3.     tempSuccessList.Add(new NativeArray<bool>(succesList[i], Allocator.TempJob));
    4. }
    5.  
    6.  
    And then later to dispose of this newly copied array, I call on

    Code (CSharp):
    1.  
    2. private void ClearTempResultsList()
    3. {
    4.     for(int i = 0, l = tempSuccessList.Count; i < l; i++)
    5.    {
    6.       if(tempSuccessList[i].IsCreated)
    7.          tempSuccessList[i].Dispose();
    8. }
    And then when I call the above code, IsCreated is returned as true, but I am unable to dispose of the floorTempSuccess saying that tempSuccessList was already disposed (which the original successList was disposed).

    Why is IsCreated true if the object has already been disposed?
     
  2. 8bitgoose

    8bitgoose

    Joined:
    Dec 28, 2014
    Posts:
    448
    Well, I am a bit of a dummy. I was forgetting to clear the list after I disposed each array.

    Although I still think if you call IsCreated on a disposed native array it should return false. Is this not the intended behaviour?
     
  3. tim_jones

    tim_jones

    Unity Technologies

    Joined:
    May 2, 2019
    Posts:
    287
    Is tempSuccessList a List<NativeArray<bool>>, by any chance? If so, I think that's the problem, because NativeArray<bool> is a value type, not a reference type. So when you call tempSuccessList.Dispose() you're modifying a copy-by-value copy of the NativeArray<bool>, which wouldn't change the one stored in tempSuccessList.

    But in general, yes, putting the NativeArray.Dispose() call behind an IsCreated check should work.
     
  4. 8bitgoose

    8bitgoose

    Joined:
    Dec 28, 2014
    Posts:
    448
    Oh shoot, yes it is.

    Is there a way to hold a list of NativeArrays without messing something up and being able to access the direct data? I thought that the NativeArray was a reference that you can pass around. I need to have many native arrays in a list that I run parallel jobs over and then later dispose them. Always on the main thread, so I am not passing the list into a job.
     
  5. tim_jones

    tim_jones

    Unity Technologies

    Joined:
    May 2, 2019
    Posts:
    287
    Must it be a List<NativeArray<bool>>? Could it instead be a NativeArray<bool>[] ? Array indexers are a bit special-cased in C# in that they return the element by reference, so it should just work.
     
  6. 8bitgoose

    8bitgoose

    Joined:
    Dec 28, 2014
    Posts:
    448
    Unfortunately yes. I need to be able to keep adding to the list as needed. I could probably write a wrapper to treat it as a array and expand the array when needed, but that is a bit of a pain. Although for whatever reason, I am not getting any disposal errors now. So it looks like I am successfully clearing as the NativeArrays I've made.

    Is there any chance the Disposal Sentinel isn't finding these extra arrays?
     
  7. tim_jones

    tim_jones

    Unity Technologies

    Joined:
    May 2, 2019
    Posts:
    287
    When you call Dispose() on the item in the List<T>, it would actually dispose the unmanaged memory, which is probably why DisposeSentinel doesn't complain. But the item in the List<T> hasn't been modified, so it would still return true for IsCreated.

    A workaround would be:

    Code (CSharp):
    1. var myItem = myList[0];
    2. myItem.Dispose();
    3. myList[0] = myItem;
     
  8. 8bitgoose

    8bitgoose

    Joined:
    Dec 28, 2014
    Posts:
    448
    Oh heck yeah, this is perfect. That makes total sense. I am still a bit shaky on how Native Arrays are stored but this is exactly why IsCreate is returning true while I am still able to dispose the list.

    Thanks so much!
     
    tim_jones likes this.
  9. 8bitgoose

    8bitgoose

    Joined:
    Dec 28, 2014
    Posts:
    448
    I have another question about NativeArrays. I want to extend NativeArray to a new native Array called NativeArrayList. Basically NativeList, but with the ability to insert and a few of the other options that List<> has in C#.

    I've already implemented it a bit as a struct with an underlying NativeArray which I resize and dispose as needed. Am I doing this the right way? I sometimes get weird situations like those of above where I call on the underlying list as being created but then throws an error when I try to dispose the underlying array.

    I guess my question is what is the best way to extend NativeArrays and write my own type?

    Should I be looking at this instead of making a struct wrapper?

    https://www.jacksondunstan.com/articles/4734
     
  10. tim_jones

    tim_jones

    Unity Technologies

    Joined:
    May 2, 2019
    Posts:
    287
    What is it specifically that you're missing in NativeList? There are some helpful extension methods here:

    https://forum.unity.com/threads/nativelist-remove-and-removeat-methods.778859/#post-5183357

    NativeList itself has an InsertRangeWithBeginEnd() method, which I guess could be used to implement a normal Insert() method?

    Since you're in the Burst forum, I'll mention that built-in collections like NativeArray and NativeList have some built-in niceties in Burst, like alias checking to make it more likely that loops will be vectorized. You can technically build this yourself for your own collection types - see here for details - but it's non-trivial to get it right.
     
    Last edited: Jun 10, 2021
  11. 8bitgoose

    8bitgoose

    Joined:
    Dec 28, 2014
    Posts:
    448
    Oh wow, those extensions were exactly what I was looking for. I am trying to keep my code really simple so it can be used even with older versions of Unity (2019) so I wasn't pulling in any fancy lists or what have you.

    I was just using lists on the main thread, not putting them into jobs. I would convert into a NativeArray before jobifying them. I started with Burst a year and a bit ago, so I am sure the features have grown since I last looked into NativeList.

    Am I able to wrap a NativeArray in another struct (Native Array lives inside the struct) or will this cause major issues with copying and moving data around?