Search Issue Tracker
By Design
By Design in 1.8.X
Votes
0
Found in [Package]
1.8.4
Issue ID
TB-212
Regression
No
TimelineAssets can't be removed from the memory when using "Resources.UnloadUnusedAssets"
How to reproduce:
1. Open project "TimelineAssetLeak.zip"
2. Go to Window > Asset Management > Addressables > Groups
3. Press Build > New Build > Default Build Script
4. In the Editor Menu press Leak > Show Timeline Asset Count
5. Observe the number in the Console window
6. In the Menu press Leak > Unload and GC
7. Repeat 4th and 5th steps
Expected result: Timeline Asset Count is 0
Actual result: Timeline Asset Count is 5
Reproducible with: 1.8.3, 1.8.4 (2021.3.28f1, 2022.3.4f1, 2023.1.3f1, 2023.2.0a21)
Notes from the user:
- Not only TimelineAssets but also the Tracks and Clips on the Timeline won't be removed from the memory
- Projects with a huge amount of Timeline Clips will run out of memory when building
Add comment
All about bugs
View bugs we have successfully reproduced, and vote for the bugs you want to see fixed most urgently.
Latest issues
- Out-of-bounds memory access with multiple CanvasRenderers under a Canvas when using Mesh API
- Inspector tries to access file after it was deleted when the file was locked in Inspector window
- Changing Transform values in Search window Inspector loses focus while dragging and stopping mouse without releasing dragging action
- Saving changes on the dirty VFX Graph during the Play mode throws "The referenced script (Unknown) on this Behaviour is missing!" warnings
- VFX Graph Debug Info overlaps the "Initialize" block debug info by default
Resolution Note:
In the attached project there are 5 Timeline Assets, and 2 menu item actions. One outputs the number of loaded Timeline Assets (via Resources.FindObjectsOfTypeAll<TimelineAsset>()), and another that unloads unused resources and tells the Garbage Collector to run.
Resources.UnloadUnusedAssets() returns a reference to an asynchronous coroutine. In the example code, the call to GC.Collect happens on the next line, so it's unlikely that this coroutine has had a chance to finish. I've done some quick modifications and get a final output of "In memory TimelineAsset count: 0".
using UnityEditor;
using UnityEngine;
using UnityEngine.Timeline;
public static class DisplayTimelineObjectCount
{
[MenuItem("Leak/Show Timeline Asset Count")]
private static void Display()
{
DebugOutput();
}
[MenuItem("Leak/Unload And GC")]
private static void UnloadAndGC()
{
AsyncOperation operation = Resources.UnloadUnusedAssets();
operation.completed += (_) =>
{
System.GC.Collect();
EditorApplication.delayCall += DebugOutput;
};
}
static void DebugOutput()
{
var assets = Resources.FindObjectsOfTypeAll<TimelineAsset>();
Debug.LogWarning($"In memory TimelineAsset count: {assets.Length}");
foreach (var ta in assets)
{
Debug.Log($"Found Asset : {ta.name}");
}
}
}
If, instead of immediately trying to invoke the GC , you wait for the UnloadUnusedAssets coroutine to complete, you should see all your assets get collected.
Resolution Note (1.8.X):
In the attached project there are 5 Timeline Assets, and 2 menu item actions. One outputs the number of loaded Timeline Assets (via Resources.FindObjectsOfTypeAll<TimelineAsset>()), and another that unloads unused resources and tells the Garbage Collector to run.
Resources.UnloadUnusedAssets() returns a reference to an asynchronous coroutine. In the example code, the call to GC.Collect happens on the next line, so it's unlikely that this coroutine has had a chance to finish. I've done some quick modifications and get a final output of "In memory TimelineAsset count: 0".
using UnityEditor;
using UnityEngine;
using UnityEngine.Timeline;
public static class DisplayTimelineObjectCount
{
[MenuItem("Leak/Show Timeline Asset Count")]
private static void Display()
{
DebugOutput();
}
[MenuItem("Leak/Unload And GC")]
private static void UnloadAndGC()
{
AsyncOperation operation = Resources.UnloadUnusedAssets();
operation.completed += (_) =>
{
System.GC.Collect();
EditorApplication.delayCall += DebugOutput;
};
}
static void DebugOutput()
{
var assets = Resources.FindObjectsOfTypeAll<TimelineAsset>();
Debug.LogWarning($"In memory TimelineAsset count: {assets.Length}");
foreach (var ta in assets)
{
Debug.Log($"Found Asset : {ta.name}");
}
}
}
If, instead of immediately trying to invoke the GC , you wait for the UnloadUnusedAssets coroutine to complete, you should see all your assets get collected.