#Entities `1.0.14 'Leaks' from DynamicBuffer.CopyFrom and DynamicBuffer.AddRange

1 messages · Page 1 of 1 (latest)

warm scaffold
#

AddRange

Found 386 leak(s) from callstack:
0x00007fff99e749a1 (9d2c57e040d3c7348cfa2d887a17a13) Unity.Entities.DynamicBuffer`1<Unity.Entities.Entity>.AddRange (at I:/Documents/BovineLabs/com.bovinelabs.effects/Library/PackageCache/com.unity.burst@1.8.8/.Runtime/Library/PackageCache/com.unity.entities@1.0.14/Unity.Entities/Iterators/DynamicBuffer.cs:386)```
CopyFrom
```cs
Found 8 leak(s) from callstack:
0x00007fff99e7438f (9d2c57e040d3c7348cfa2d887a17a13) Unity.Entities.DynamicBuffer`1<BovineLabs.Stats.Data.Stat>.CopyFrom (at I:/Documents/BovineLabs/com.bovinelabs.effects/Library/PackageCache/com.unity.burst@1.8.8/.Runtime/Library/PackageCache/com.unity.entities@1.0.14/Unity.Entities/Iterators/DynamicBuffer.cs:622)```
#

I don't get how this is possible?

#

One thing to note is these are buffers created from ECB that haven't been played back yet

#

Going to look into a simple repo

warm scaffold
#

easy to repo

#
public partial struct TestSystem : ISystem
{
    private EntityArchetype archetype;

    public void OnCreate(ref SystemState state)
    {
        this.archetype = state.EntityManager.CreateArchetype(typeof(Buffer));
    }

    [BurstCompile]
    public void OnUpdate(ref SystemState state)
    {
        var ecbs = SystemAPI.GetSingleton<EndInitializationEntityCommandBufferSystem.Singleton>();
        var data = CollectionHelper.CreateNativeArray<int>(1234, state.WorldUpdateAllocator);

        state.Dependency = new Job
            {
                Archetype = this.archetype,
                CommandBuffer = ecbs.CreateCommandBuffer(state.WorldUnmanaged),
                Data = data,
            }
            .Schedule(state.Dependency);
    }

    [BurstCompile]
    private struct Job : IJob
    {
        public EntityArchetype Archetype;

        public EntityCommandBuffer CommandBuffer;

        public NativeArray<int> Data;

        public void Execute()
        {
            var e1 = this.CommandBuffer.CreateEntity(this.Archetype);
            var b1 = this.CommandBuffer.SetBuffer<Buffer>(e1).Reinterpret<int>();
            b1.AddRange(this.Data);

            var e2 = this.CommandBuffer.CreateEntity(this.Archetype);
            var b2 = this.CommandBuffer.SetBuffer<Buffer>(e2).Reinterpret<int>();
            b2.CopyFrom(this.Data);
        }
    }

    [InternalBufferCapacity(1)]
    public struct Buffer : IBufferElementData
    {
        public int Value;
    }
}```
#
0x00007ff823362ad1 (16e4ca8157ee87e8d9977530ff90bc7) Unity.Entities.DynamicBuffer`1<int>.AddRange (at I:/Documents/Demos/Entities/Library/PackageCache/com.unity.burst@1.8.8/.Runtime/Library/PackageCache/com.unity.entities@1.0.14/Unity.Entities/Iterators/DynamicBuffer.cs:386)```
```Found 1 leak(s) from callstack:
0x00007ff823362c2f (16e4ca8157ee87e8d9977530ff90bc7) Unity.Entities.DynamicBuffer`1<int>.CopyFrom (at I:/Documents/Demos/Entities/Library/PackageCache/com.unity.burst@1.8.8/.Runtime/Library/PackageCache/com.unity.entities@1.0.14/Unity.Entities/Iterators/DynamicBuffer.cs:595)```
#

ahhhh, this is actually caused by

var ecbs = SystemAPI.GetSingleton<EndInitializationEntityCommandBufferSystem.Singleton>();```
Swapping to 
```cs
var ecbs = SystemAPI.GetSingleton<EndSimulationEntityCommandBufferSystem.Singleton>();```
seems to remove leak
#

something doesn't seem to be cleaning up correctly in world shutdown so I still consider this a bug

#

@brisk osprey @shrewd basin i think one of you handle this type of stuff? 🙃

misty vessel
warm scaffold
#

there are 5 core buffers
begin/end init
begin/end sim
begin pres

misty vessel
#

is there ever a case when EndInitializationECBS and BeginSimulationECBS don't execute both (assuming there's stuff to do), and in this exact order? (sorry, didn't intend to hijack thread)

warm scaffold
#

yes you can inject systems in between them

#

netcode puts a system before begin simulation, for example

#

[UpdateInGroup(typeof(SimulationSystemGroup), OrderFirst=true)]
[UpdateBefore(typeof(BeginSimulationEntityCommandSystem))]

brisk osprey
#

Yup, this looks legit; The DynamicBuffers created & manipulated during ECB recording are expected to be "owned" by the entities that are created for them during ECB playback. If the buffer isn't played back (for whatever reason -- world is destroyed, Playback() is never called, etc.), those DynamicBuffer allocations will leak. I'll file a bug; thank you!

brisk osprey
#

@warm scaffold It looks like the DynamicBuffer tracking I mentioned should already be happening, so there must be something else going on. I'm trying to get your repro case working; as written, if I update TestSystem once and then dispose the world, I get an error that nothing is completing the job it schedules:

ArgumentException : The previously scheduled job DynamicBufferLeakTestSystem:Job writes to the Unity.Entities.EntityCommandBuffer Job.CommandBuffer. You must call JobHandle.Complete() on the job DynamicBufferLeakTestSystem:Job, before you can deallocate the Unity.Entities.EntityCommandBuffer safely.
EntityCommandBuffer was recorded in Unity.Entities.Tests.EntityCommandBufferTests+DynamicBufferLeakTestSystem and disposed in Unity.Entities.EndInitializationEntityCommandBufferSystem.

(...which I suppose would also be a world-disposal bug; when disposing ECB systems, they must complete jobs that are writing their ECBs before trying to play back those ECBs. But that's not the bug you're seeing.)

warm scaffold
brisk osprey
#

Hmm, I'm trying to implement it as a unit test that ticks the ECB system once, then ticks the test system once, then disposes the world.

#

And strangely, I'm not getting the job error any more, but I am finally seeing the leak. Ah well, disregard, back to the investigation!

warm scaffold
#

Ah OK, good you can repo!