单例模式解决无法访问已释放的对象

本文介绍了一种使用C#实现泛型单例模式的方法,该模式确保了整个应用程序中只有一个实例存在,并提供了对该实例的全局访问点。此外,还实现了资源释放时对象的清理机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

在 Unity 中使用单例模式时,由于其全局生命周期特性,如果不正确释放对象引用,容易导致内存泄漏。以下是一些常见的释放方法和优化策略。 ### 1. **静态引用手动置空** 对于继承 `MonoBehaviour` 的单例类,通常会将实例存储在一个静态字段中,例如: ```csharp public class Singleton : MonoBehaviour { private static Singleton instance; public static Singleton Instance => instance; public void Awake() { if (instance == null) { instance = this; DontDestroyOnLoad(gameObject); } else { Destroy(gameObject); } } public void OnDestroy() { if (instance == this) { instance = null; } } } ``` 在场景切换或应用退出时,可以通过调用 `Destroy()` 方法销毁单例对象,并在 `OnDestroy()` 中将静态引用置空,以确保不会残留无效引用[^1]。 ### 2. **泛型单例模板的显式销毁** 对于不继承 `MonoBehaviour` 的泛型单例基类,如: ```csharp public class Singleton<T> where T : Singleton<T> { private static T instance; public static T Instance { get { if (instance == null) { instance = Activator.CreateInstance(typeof(T), true) as T; } return instance; } } protected Singleton() { } } ``` 由于此类单例不依赖于 GameObject 生命周期,需要提供一个显式的销毁方法,例如: ```csharp public class Singleton<T> where T : Singleton<T> { private static T instance; public static T Instance { get { if (instance == null) { instance = Activator.CreateInstance(typeof(T), true) as T; } return instance; } } public static void Release() { instance = null; } protected Singleton() { } } ``` 在不再需要该单例时,调用 `Release()` 方法即可释放引用[^3]。 ### 3. **使用锁机制确保线程安全** 某些情况下,单例可能被多个线程访问,因此需确保释放操作的线程安全性。可以使用 `lock` 语句来避免多线程冲突: ```csharp private static readonly object sysLock = new object(); private static T _instance; public static T GetInstance() { if (_instance == null) { lock (sysLock) { if (_instance == null) { _instance = new T(); } } } return _instance; } public static void ReleaseInstance() { lock (sysLock) { _instance = null; } } ``` 此方式适用于通用单例模板,可确保在多线程环境下安全地释放引用[^2]。 ### 4. **结合资源管理器统一释放** 对于涉及资源加载的单例(如资源管理器、音频管理器等),应在释放单例前先清理其持有的资源,例如: ```csharp public class ResourceManager : Singleton<ResourceManager> { private Dictionary<string, Object> loadedAssets = new Dictionary<string, Object>(); public void LoadAsset(string path) { var asset = Resources.Load(path); if (!loadedAssets.ContainsKey(path)) { loadedAssets[path] = asset; } } public void ClearAllAssets() { foreach (var asset in loadedAssets.Values) { Resources.UnloadAsset(asset); } loadedAssets.Clear(); } public override void Release() { ClearAllAssets(); base.Release(); } } ``` 这种方式确保了在释放单例前,所有关联资源都被正确卸载,从而避免资源泄漏。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值