双向链表的作用

双向链表用来配合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);//+++
//释放Asset Bundle引用
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;

我们可以根据低配、中配、高配来设置不同的资源限制个数

然后完成ResourceManagerWashOut方法

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后,剩余的资源依然比内存容量限制多,造成死循环。