Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

High memory allocations when unregistering delegates from event in C#

Tags:

c#

mono

unity3d

We are developing a game with the Unity3D engine (which uses Mono for user code - our code is written in C#).

The scenario is that we have a class exposing an event, with around ~ 250 registrations to that event (each level object on the game's map registers itself to that event):

// Every level registers itself (around 250 levels)
ScoresDataHelper.OnScoresUpdate += HandleOnScoresUpdate;

When destroying this scene, every object unregisters itself from the event:

ScoresDataHelper.OnScoresUpdate -= HandleOnScoresUpdate;

When using the built-in profiler, i am seeing a huge memory allocation, digging deeper shows that it is due to the delegates being unregistered.

I suspect this is due to the fact that Delegates are immutable and when chaining them together, new instances are created ?

Here's a screenshot from Unity's profiler:

Profiler

Is there any way to avoid these memory allocations when dealing with a large number of event subscriptions?

like image 403
lysergic-acid Avatar asked Apr 12 '15 08:04

lysergic-acid


2 Answers

As you confirmed in comments that you want to unsubscribe all the event subscriptions, there is no reason to unsubscribe it one by one.

You could just set the event to null. This will unsubscribe everything from the event without allocating any memory.

this.OnScoresUpdate = null;

One thing to note is that you can't do this from outside of the ScoresDataHelper class. It must be inside ScoresDataHelper class.

like image 98
Sriram Sakthivel Avatar answered Nov 12 '22 03:11

Sriram Sakthivel


A simple solution would be not to use events in the first place.

// T,S,U is whatever your function takes and returns
private List<Func<T,S,U>> Listeners = new List<Func<T,S,U>>();
public void OnScoresUpdate(Func<T,S,U> listener){
    Listeners.Add(listener);
}

// when you want to fire the event
foreach(var listener in Listeners){
    listener(param1, param2);
}

// when you want to unsubscribe the listeners:
Listeners = new List<Func<T,S,U>>();

You can also use a weak collection if you want to avoid memory issues, removing listeners automatically as soon as the element gets garbage collected.

like image 33
Benjamin Gruenbaum Avatar answered Nov 12 '22 01:11

Benjamin Gruenbaum