gameObject.renderer.enabled
//是控制一個物體是否在屏幕上渲染或顯示 而物體實際還是存在的 只是想當於隱身 而物體本身的碰撞體還依然存在的
GameObject.Destroy()
//表示移除物體或物體上的組件 代表銷毀該物體 實際上該物體的內存並沒有立即釋放 而是在你下下個場景中槽釋放內存資源,就是你a場景中Destroy了 一般是在c場景中才真正釋放該物體的內存資源(這是我的體會 不知道理解錯誤沒)
gameObject.active
//是否在場景中停用該物體 在你gameObject.active =false中 則你在場景中用find找不到該物體
//如果該物體有子物體 你要用SetActiveRecursively(false) 來控制是否在場景中停用該物體(遞歸的)
我們要介紹是銷毀物體Destroy()
1 using UnityEngine; 2 using System.Collections; 3 4 public class acc : MonoBehaviour { 5 6 // Use this for initialization 7 public Transform Q; 8 int speed=50; 9 void Start () { 10 11 } 12 13 // Update is called once per frame 14 void Update () { 15 float x = Input.GetAxis("Horizontal") * Time.deltaTime * speed;//左右移動 16 float z = Input.GetAxis("Vertical") * Time.deltaTime * speed;// 前后移動 17 //主攝像機物體 移動 18 transform.Translate(x,0,z); 19 20 if(Input.GetKeyDown(KeyCode.Mouse0)) 21 { 22 23 //實列化子彈 24 Transform n = Instantiate(Q) as Transform; 25 //發射子彈的位置為物體的位置 26 n.position = transform.position; 27 28 Vector3 f = transform.TransformDirection(Vector3.forward); 29 n.gameObject.rigidbody.AddForce(f*3000); 30 Destroy(n.gameObject,5); 31 //Destroy(n.gameObject); 32 //Destroy(gameObject); 33 } 34 35 36 } 37 }
5秒后 銷毀物體
Destroy(n.gameObject,5);
立即銷毀物體
Destroy(n.gameObject);
如果文件綁定在物體上用
Destroy(gameObject);
來銷毀物體
Unity資源內存申請和釋放
1.資源類型
GameObject, Transform, Mesh, Texture, Material, Shader, Script和各種其他Assets。
2.資源創建方式
- 靜態引用,在腳本中加一個public GameObject變量,在Inspector面板中拖一個prefab到該變量上,然后在需要引用的地方Instantiate;
- Resource.Load,資源需要放在Assets/Resources目錄下;
- AssetBundle.Load, Load之后Instantiate。
3. 資源銷毀方式
- GameObject.Destroy(gameObject),銷毀該物體;
- AssetBundle.Unload(false),釋放AssetBundle文件內存鏡像,不銷毀Load創建的Assets對象;
- AssetBundle.Unload(true),釋放AssetBundle文件內存鏡像同時銷毀所有已經Load的Assets內存鏡像;
- Resources.UnloadAsset(Object),釋放已加載的Asset對象;
- Resources.UnloadUnusedAssets,釋放所有沒有引用的Asset對象。
4. 生命周期
實驗篇
實驗中創建了一個簡單場景,場景中創建了一個Empty GameObject,上面掛了一個腳本,在Awake函數中通過協程函數來創建資源,具體的Coroutine函數下面都有。 實驗中創建的Prefab是一個坦克車,加入場景中場景內存增加3M左右,同時創建了一個AssetBundle資源供AssetBundle使用。1. Resources.Load方式加載一個Prefab, 然后Instantiate GameObject
代碼如下:
IEnumerator LoadResources()
{
// 清除干凈以免影響測試結果
Resources.UnloadUnusedAssets();
// 等待5秒以看到效果
yield return new WaitForSeconds(5.0f);
// 通過Resources.Load加載一個資源
GameObject tank = Resources.Load("Role/Tank") as GameObject;
yield return new WaitForSeconds(0.5f);
// Instantiate一個資源出來
GameObject tankInst = GameObject.Instantiate(tank, Vector3.zero, Quaternion.identity) as GameObject;
yield return new WaitForSeconds(0.5f);
// Destroy一個資源
GameObject.Destroy(tankInst);
yield return new WaitForSeconds(0.5f);
//釋放無用資源
tank = null;
Resources.UnloadUnusedAssets();
yield return new WaitForSeconds(0.5f);
}
執行結果如下:
下面是統計結果:
數據描述 | Memory | Texture | Mesh | Material | GameObjects | Objects in Scene | Total Objects |
---|---|---|---|---|---|---|---|
初始 | 72.8M | 1271/8.0M | 35/223.0K | 25/10.2K | 7 | 211 | 2187 |
Resources.Load | 72.8M | 1271/8.0M | 36/0.8M | 25/10.2K | 7 | 211 | 2280 |
Instantiate | 75.3M | 1272/9.3M | 36/0.8M | 26/10.7K | 52 | 303 | 2375 |
Destroy | 74.7M | 1272/9.3M | 36/0.8M | 26/10.7K | 7 | 211 | 2283 |
Resources.UnloadUnusedAssets | 72.3M | 1271/8.0M | 35/223.0K | 25/10.2K | 7 | 211 | 2187 |
從這里我們得出如下結論:
- Resouces.Load一個Prefab相對於Instantiate一個資源來說是相對輕量的一個操作,上述過程中,Resources.Load加載一個Prefab幾乎沒有消耗內存,而Instantiate消耗了2.5M的資源空間。Resources.Load增加了Mesh和Total Object的數量,而Instantiate增加了GameObjects,Objects In Scene和Total Objects的數量;
- Destroy一個GameObject之后,內存有所減少,但是比較少,本例中減少了0.6M;Instantiate和Destroy前后Material和Texture沒有還原,用以后面繼續進行Instantiate之用。
若沒有調用Resources.UnloadUnusedAssets,則結果如下:
統計結果如下:
數據描述 | Memory | Texture | Mesh | Material | GameObjects | Objects in Scene | Total Objects |
---|---|---|---|---|---|---|---|
初始 | 58.9M | 1258/7.5M | 34/219.2K | 22/9.0K | 7 | 117 | 2078 |
Resources.Load | 60.0M | 1258/7.5M | 35/0.8M | 22/9.0K | 7 | 117 | 2171 |
Instantiate | 62.5M | 1259/8.9M | 36/0.8M | 23/9.5K | 52 | 209 | 2256 |
Destroy | 61.8M | 1259/8.9M | 35/0.8M | 23/9.5K | 7 | 117 | 2174 |
得出如下結論: 如果不手動執行Resources.UnloadUnusedAssets,則多余的Mesh,Material和Object不會主動釋放。
2. 以AssetBundle.Load的方式加載一個Prefab,然后Instantiate一個GameObject
代碼如下:
IEnumerator LoadAssets(string path)
{
// 清除干凈以免影響測試結果
Resources.UnloadUnusedAssets();
// 等待5秒以看到效果
yield return new WaitForSeconds(5.0f);
// 創建一個WWW類
WWW bundle = new WWW(path);
yield return bundle;
yield return new WaitForSeconds(0.5f);
// AssetBundle.Load一個資源
Object obj = bundle.assetBundle.Load("tank");
yield return new WaitForSeconds(0.5f);
// Instantiate一個資源出來
GameObject tankInst = Instantiate(obj) as GameObject;
yield return new WaitForSeconds(0.5f);
// Destroy一個資源
GameObject.Destroy(tankInst);
yield return new WaitForSeconds(0.5f);
// Unload Resources
bundle.assetBundle.Unload(false);
yield return new WaitForSeconds(0.5f);
// 釋放無用資源
//obj = null;
//Resources.UnloadUnusedAssets();
yield return new WaitForSeconds(0.5f);
}
執行結果如下:
統計結果如下:
數據描述 | Memory | Texture | Mesh | Material | GameObjects | Objects in Scene | Total Objects |
---|---|---|---|---|---|---|---|
初始 | 59.9M | 1267/7.8M | 35/223.0K | 25/10.2K | 7 | 127 | 2099 |
new WWW | 62.0M | 1267/7.8M | 35/223.0K | 25/10.2K | 7 | 127 | 2099 |
AssetBundle.Load | 64.5M | 1268/9.2M | 36/0.8M | 26/10.5K | 7 | 127 | 2196 |
Instantiate | 65.6M | 1268/9.2M | 36/0.8M | 26/10.7K | 52 | 219 | 2288 |
Destroy | 63.9M | 1268/9.2M | 36/0.8M | 26/10.7K | 7 | 127 | 2196 |
AssetBundle.Unload | 63.7M | 1268/9.2M | 36/0.8M | 26/10.7K | 7 | 127 | 2196 |
Resources.UnloadUnusedAssets | 61.8M | 1267/7.8M | 35/223.0K | 25/10.2K | 7 | 127 | 2099 |
得出如下結論: 通過WWW Load AssetBundle的方式加載一個資源時會自動加載相應的Mesh,Texture和Material,而通過Resouces.Load方式進行加載只會加載Mesh信息。因此通過AssetBundle方式加載后Instantiate一個資源的內存消耗較小,本例中AssetBundle.Load增加了2.5M的內存,而Instantiate增加了1.1M的內存。相比較Resources.Load后Instantiate的內存增量要小很多。
3. 通過靜態綁定的方法來Instantiate一個資源
代碼如下:
IEnumerator InstResources()
{
Resources.UnloadUnusedAssets();
yield return new WaitForSeconds(5.0f);
GameObject inst = GameObject.Instantiate(tank, Vector3.zero, Quaternion.identity) as GameObject;
yield return new WaitForSeconds(1f);
GameObject.Destroy(inst);
yield return new WaitForSeconds(1f);
//釋放無用資源
tank = null;
Resources.UnloadUnusedAssets();
yield return new WaitForSeconds(1f);
}
執行結果如下:
統計結果如下:
數據描述 | Memory | Texture | Mesh | Material | GameObjects | Objects in Scene | Total Objects |
---|---|---|---|---|---|---|---|
初始 | 62.0M | 1268/7.9M | 36/0.8M | 25/10.2K | 7 | 134 | 2202 |
Instantiate | 64.4M | 1269/9.2M | 36/0.8M | 26/10.7K | 8 | 137 | 2207 |
Destroy | 64.0M | 1269/9.2M | 36/0.8M | 26/10.7K | 7 | 134 | 2204 |
UnloadUnused Resources | 62.3M | 1268/7.9M | 35/226.3K | 25/10.2K | 7 | 134 | 2107 |
得出結論如下: 通過靜態綁定的方式各種資源的加載順序和Resources.Load的方式是一樣的,一個GameObject創建時,其Component中靜態綁定的GameObject只會加載Mesh信息,只有當該GameObject Instantiate出來之后才會加載Texture和Material信息。
理論篇
加載資源的過程可以分為兩個階段,第一階段是使用Resources.Load或者AssetBundle.Load加載各種資源,第二階段是使用GameObject.Instantiate克隆出一個新的GameObject。 Load的資源類型包括GameObject, Transform, Mesh, Texture, Material, Shader和Script等各種資源,但是Resources.Load和AssetBundle.Load是有區別的。 使用Resources.Load的時候在第一次Instantiate之前,相應的Asset對象還沒有被創建,直到第一次Instantiate時才會真正去讀取文件創建這些Assets。它的目的是實現一種OnDemand的使用方式,到該資源真正使用時才會去創建這些資源。 而使用AssetBundle.Load方法時,會直接將資源文件讀取出來創建這些Assets,因此第一次Instantiate的代價會相對較小。 上述區別可以幫助我們解釋為什么發射第一發子彈時有明顯的卡頓現象的出現。
然后我們再來了解一下Instantiate的過程。Instantiate的過程是一個對Assets進行Clone(復制)和引用相結合的過程,Clone的過程需要申請內存存放自己的數據,而引用的過程只需要直接一個簡單的指針指向一個已經Load的資源即可。例如Transform是通過Clone出來的,Texture和TerrainData是通過引用復制的,而Mesh,Material,PhysicalMaterial和Script是Clone和引用同時存在的。以Script為例,Script分為代碼段和數據段,所有需要使用該Script的GameObject使用的代碼是一樣的,而大家的數據有所區別,因此對數據段需要使用Clone的方式,而對代碼段需要使用引用的方式來復制。 因此Load操作其實Load一些數據源出來,用於創建新對象時被Clone或者被引用。
然后是銷毀資源的過程。當Destory一個GameObject或者其他實例時,只是釋放實例中那些Clone出來的Assets,而並不會釋放那些引用的Assets,因為Destroy不知道是否有其他人在引用這些Assets。等到場景中沒有任何物體引用到這些Assets之后,它們就會成為UnusedAssets,此時可以通過Resources.UnloadUnusedAssets來進行釋放。AssetBundle.Unload(false)不行,因為它只會釋放文件的內存鏡像,不會釋放資源;AssetBunde.Unload(true)也不行,因為它是暴力的釋放,可能有其他對象在引用其中的Assets,暴力釋放可能導致程序錯誤。 另外需要注意,系統在加載新場景時,所有的內存對象都會被自動銷毀,這包括了Resources.Load加載的Assets, 靜態綁定的Assets,AssetBundle.Load加載的資源和Instantiate實例化的對象。但是AssetBundle.Load本身的文件內存鏡像(用於創建各種Asset)不會被自動銷毀,這個必須使用AssetBundle.Unload(false)來進行主動銷毀。推薦的做法是在加載完資源后立馬調用AssetBunble.Unload(false)銷毀文件內存鏡像。 下圖可以幫助理解內存中的Asset和GameObject的關系。
總結篇
- 為了不出現首次Instantiate時卡頓的現象,推薦使用AssetBundle.Load的方式代替Resources.Load的方式來加載資源;
- 加載完資源后立馬調用AssetBunble.Unload(false)釋放文件內存鏡像;
- Unity自身沒有提供良好的內存申請和釋放管理機制,Destroy一個GameObject會馬上釋放內存而不是進行內部的緩存,因此應用程序對頻繁不用的對象如NPC,FX等進行對象池管理是必要的,減少內存申請次數;
- 何時進行Resources.UnloadUnusedAssets是需要討論的一個問題。
520 520小說 小說520 小說520 5200 小說5200 5200小說 5200小說網
www.520books.com
http://www.cnblogs.com/goodchenqing/
http://blog.sina.com.cn/goodchenqing
http://goodchenqing.bokee.com/
http://blog.csdn.net/abc288abcd/article/category/2786567