Hello guys, I'm inspecting my code for a memory leak. I'm not sure is it really there but what I catch during testing is that used memory increasing every time new music track is loaded. It would be really nice if somebody with a sharp eye can inspect this piece of code and say is there a memory leak. (Unity 2017.4.0f1) Code (CSharp): using System.Collections.Generic; using System.IO; using System.Linq; using UnityEngine; using UnityEngine.UI; public class MusicPlayer : MonoBehaviour { public enum SeekDirection { Forward, Backward } private string _absolutePath = "./music"; [SerializeField] [HideInInspector] private int _currentIndex; private FileInfo[] _soundFiles; private readonly List<string> _validExtensions = new List<string> {".ogg"}; public AudioClip ClipToPlay; public Text MusicName; public ParticleSystem prt; public AudioSource source; private void Start() { if (Application.isEditor) _absolutePath = "Assets/"; if (source == null) source = gameObject.AddComponent<AudioSource>(); ReloadSounds(); PlayCurrent(); } private void FixedUpdate() { if (!source.isPlaying) { Seek(SeekDirection.Forward); PlayCurrent(); } } private void Seek(SeekDirection d) { if (d == SeekDirection.Forward) { _currentIndex = (_currentIndex + 1) % _soundFiles.Length; } else { _currentIndex--; if (_currentIndex < 0) _currentIndex = _soundFiles.Length - 1; } } private void PlayCurrent() { ClipToPlay = LoadClip(_soundFiles[_currentIndex].FullName); source.clip = ClipToPlay; source.Play(); prt.Simulate(0, true, true); prt.Play(true); MusicName.text = ClipToPlay.name.Replace(".ogg", ""); ReloadSounds(); } private void ReloadSounds() { var info = new DirectoryInfo(_absolutePath); _soundFiles = info.GetFiles() .Where(f => IsValidFileType(f.Name)) .ToArray(); } private bool IsValidFileType(string fileName) { return _validExtensions.Contains(Path.GetExtension(fileName)); } private AudioClip LoadClip(string path) { var www = new WWW("file://" + path); Debug.Log("loading " + path); var clip = www.GetAudioClip(false); while (clip.loadState != AudioDataLoadState.Loaded) { } clip.name = Path.GetFileName(path); return clip; } }
I haven't fiddled with Unity's file management system yet, but if I had to guess, I noticed that AudioClips have a method called UnloadAudioData(). Perhaps you could try calling this at the start of your LoadClip method and see if it makes a difference: Code (CSharp): private AudioClip LoadClip(string path) { ClipToPlay.UnloadAudioData(); //The rest of your code } Or alternatively, I wouldn't use a global AudioClip variable in the first place here, since you are returning a local AudioClip in your LoadClip method. In your PlayCurrent method, instead of this: Code (CSharp): ClipToPlay = LoadClip(_soundFiles[_currentIndex].FullName); source.clip = ClipToPlay; I would do this: Code (CSharp): source.clip = LoadClip(_soundFiles[_currentIndex].FullName); That way your AudioSource is using a completely new AudioClip every time you load one.
Hi, thanks for the suggestion, it actually appears that we need unload and destroy audioclip so the solution would be to add Code (CSharp): if (ClipToPlay != null && ClipToPlay.loadState == AudioDataLoadState.Loaded) { ClipToPlay.UnloadAudioData(); Destroy(ClipToPlay); } to the start of PlayCurrent(), but your suggestion have a way more logic than mine.