双向链表的作用
双向链表用来配合WashOut,将内存中一直保存的、但是很长时间没用到的资源处理掉。
修改ResourceManager的DestroyResourceItem
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| protected void DestroyResourceItem(ResourceItem item, bool destroyCache = false) { if(item == null||item.RefCount>0) { return; } if(!destroyCache) { m_NoReferenceAssetMapList.InsertToHead(item); return; } if (!AssetDic.Remove(item.m_Crc)) { return; }
m_NoReferenceAssetMapList.Remove(item); AssetBundleManager.Instance.ReleaseAsset (item);
ObjectPoolManager.Instance.ClearPool(item.m_Crc); if(item.m_Obj != null) { item.m_Obj = null; } #if UNITY_EDITOR Resources.UnloadUnusedAssets(); #endif }
|
WashOut
使用资源个数限制来WashOut
首先在ResourceManager
里面声明个数限制
1
| private const int MAXCACHECOUNT = 500;
|
我们可以根据低配、中配、高配来设置不同的资源限制个数
然后完成ResourceManager
的WashOut
方法
1 2 3 4 5 6 7 8 9 10 11 12 13
| protected void WashOut() { while(m_NoReferenceAssetMapList.Size() >= MAXCACHECOUNT) { for (int i = 0; i < MAXCACHECOUNT / 2; i++) {
ResourceItem item = m_NoReferenceAssetMapList.Back(); DestroyResourceItem(item, true); } } }
|
检查内存占用量来WashOut
首先我们需要获取在Android和IOS系统下当前游戏占用的内存。
unity3d 获取使用内存大小 android and ios_思玉的博客-CSDN博客
伪代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public static int GetUseMemory() { int memory = -1; #if UNITY_ANDROID try { AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"); AndroidJavaClass unityPluginLoader = new AndroidJavaClass("java类全名"); float tempMemory = unityPluginLoader.CallStatic<float>("GetMemory", currentActivity); memory = (int)tempMemory; } catch (System.Exception e) { ILog.Info("com.moba.unityplugin.AndroidUtile GetMemory: " + e.Message); } #elif UNITY_IOS memory = (int)_IOS_GetTaskUsedMemeory(); #endif return memory; }
|
安卓的内存访问接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public static float GetMemory(Activity currentActivity) { float memory = -1; try {
int pid = android.os.Process.myPid(); ActivityManager mActivityManager = (ActivityManager) currentActivity .getSystemService(Context.ACTIVITY_SERVICE); Debug.MemoryInfo[] memoryInfoArray = mActivityManager.getProcessMemoryInfo(new int[] { pid }); memory = (float) memoryInfoArray[0].getTotalPrivateDirty() / 1024; } catch (Exception e) { if (Utile.isDebug()) Utile.LogError(e.toString()); } return memory; }
|
IOS的内存访问接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| long _IOS_GetTaskUsedMemeory() { task_basic_info_data_t taskInfo; mach_msg_type_number_t infoCount = TASK_BASIC_INFO_COUNT; kern_return_t kernReturn = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&taskInfo, &infoCount); if (kernReturn == KERN_SUCCESS) { long usedMemory = taskInfo.resident_size/1024.0/1024.0; return usedMemory; } return 0; }
|
我们可以根据低配、中配、高配来设置不同的内存容量限制
WashOut
的伪代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| float 上一次WashOut的时间; protected void WashOut() { float 时间间隔 = Time.realTimeSinceStartUp - 上一次WashOut的时间 while(当前游戏内存 >= 内存容量限制 && 时间间隔 > 指定的数值) { for (int i = 0; i < MAXCACHECOUNT / 2; i++) {
ResourceItem item = m_NoReferenceAssetMapList.Back(); DestroyResourceItem(item, true); } 上一次WashOut的时间 = Time.realTimeSinceStartUp; } }
|
使用时间间隔是因为有可能我们根据链表清空ResourceItem后,剩余的资源依然比内存容量限制多,造成死循环。