乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      U3D內(nèi)存優(yōu)化之(四)

       kiki的號(hào) 2017-06-30

      第一篇介紹了在 .NET/Mono 和Unity里內(nèi)存管理的基礎(chǔ),并且提供了一些避免不必要的堆分配的建議。第三篇會(huì)深入到對(duì)象池。所有的都主要是面向中級(jí)的C#開發(fā)者。

      我們現(xiàn)在來(lái)看看兩種發(fā)現(xiàn)項(xiàng)目中不想要的堆分配的方法。第一種-Unity profiler-實(shí)在是太簡(jiǎn)單了,但是卻相當(dāng)費(fèi)錢,得買’pro‘版的。第二種是講你的.NET/Mono程序集反匯編成中間語(yǔ)言(CIL)然后再檢查。如果你從沒(méi)見過(guò)反匯編的.NET代碼,繼續(xù)看下去,不難,而且免費(fèi)還很有啟發(fā)意義。

      容易的方法:使用Unity profiler

      Unity優(yōu)秀的分析器主要被用來(lái)分析游戲中各種資源需要的性能和資源:著色器,紋理,音頻,游戲?qū)ο蟮鹊取H欢治銎髟诎l(fā)掘內(nèi)存上也一樣有用-跟你的C#代碼的行為有關(guān)-甚至是外部的 沒(méi)引用UnityEngine.dll的.NET/Mono程序集!在當(dāng)前Unity版本中(4.3),這個(gè)功能不是來(lái)自內(nèi)存分析器,而是CPU分析器。到C#代碼的時(shí)候,內(nèi)存分析器只是展示Mono堆的總大小和已使用的量。

      這樣讓你看你的C#代碼是否有嫩村泄露實(shí)在太粗糙了。即使不適用任何腳本,已使用的堆大小也會(huì)持續(xù)增長(zhǎng)和縮減。只要你使用腳本,你需要一個(gè)看哪里分配了內(nèi)存的途徑,然后CPU分析器剛好給你提供這個(gè)。

      讓我們來(lái)看看一些實(shí)例代碼。假設(shè)下面的腳本綁定到了一個(gè)GameObject上。

      1 using UnityEngine;using System.Collections.Generic;
      2 public class MemoryAllocatingScript : MonoBehaviour{    void Update()    {        
      3 List<int> iList = new List<int>(new int[] { 
      4 072, 101, 108, 108, 111, 032, 119, 111, 114, 108, 100, 033 });        
      5 string result = "";       
      6  foreach (int i in iList.ToArray())            
      7 result += ((char)i).ToString();       
      8  Debug.Log(result);    }}

      它所做的就是通過(guò)一組整數(shù)用一種繞的方法創(chuàng)建了一個(gè)字符串(”Hello world!”),一路上造成了不必要的內(nèi)存分配。多少呢?很高興你問(wèn)了,但是我很懶,就讓我們看看CPU分析器吧。選中窗口頂部的”Deep Profiler“,可以跟蹤到每幀的調(diào)用樹。

      正如你所見,堆內(nèi)存在Update()函數(shù)過(guò)程中的5個(gè)不同位置被分配。這個(gè)列表的初始化,foreach循環(huán)里到數(shù)組的轉(zhuǎn)換是多余的,每一個(gè)數(shù)字到字符的轉(zhuǎn)換以及連接都需要分配內(nèi)存。有趣的是,僅僅是調(diào)用Debug.Log()也會(huì)分配一大塊內(nèi)存-這點(diǎn)值得記下來(lái),即使在生產(chǎn)環(huán)境中這段代碼會(huì)被剔除。

      如果你沒(méi)有Unity Pro,但是恰巧有Microsoft Visual Studio,那就有替代Unity Profiler的方法來(lái)發(fā)掘調(diào)用堆棧。Telerik 告訴我他們的 JustTrace Memory profiler 有相似的功能 (see here). 然而, 我不知道它模仿Unity每幀記錄調(diào)用樹到了什么程度。更進(jìn)一步,盡管對(duì)Unity項(xiàng)目的遠(yuǎn)程調(diào)試(通過(guò)UnityVS) 是可以的,我還是沒(méi)有成功的把JustTrace用來(lái)分析被Unity調(diào)用的程序集。

      只是稍微難一點(diǎn)點(diǎn)的方法:反匯編你的代碼

      CIL的背景知識(shí)

      如果你已經(jīng)有了一個(gè).NET/Mono的反匯編器,開始用吧,不然我推薦ILSpy. 這個(gè)工具不僅是免費(fèi)的,它還非常干凈簡(jiǎn)單,但是剛好包含下面我們會(huì)用到的一個(gè)特殊功能。

      你也許知道C#編譯器不會(huì)將你的代碼編譯成機(jī)器語(yǔ)言,而是公共中間語(yǔ)言。這種語(yǔ)言是被原.NET團(tuán)隊(duì)作為一種包含兩種來(lái)自高級(jí)語(yǔ)言特性的低級(jí)語(yǔ)言開發(fā)出來(lái)的。一方面,它與硬件無(wú)關(guān),另一方面,它包含最適合被稱為’面向?qū)ο蟆奶匦?比如可以引用其他模塊或者類的能力。

      沒(méi)有經(jīng)過(guò)代碼模糊處理( code obfuscator )的CIL代碼是異常容易反向工程的。 許多情況下,結(jié)果幾乎和原始的C#(VB)代碼一樣。ILSpy 可以替你做這件事,但是我們僅僅反匯編代碼就可以了(ILSpy通過(guò)調(diào)用ildasm.exe來(lái)實(shí)現(xiàn),.它是NET/Mono的一部分)。讓我們從一個(gè)加兩個(gè)整數(shù)的函數(shù)開始。

      1 int AddTwoInts(int first, int second){    
      2 int result = first + second;           
      3  return result;
      4 }

      如果你愿意,你可以將這段代碼粘貼到MemoryAllocatingScript.cs文件里。然后確保Unity編譯了它,再用ILSpy打開編譯了的庫(kù)Assembly-Csharp.dll。如果你選擇AddTwoInts() 方法,你會(huì)看到下面的:

      除了藍(lán)色的關(guān)鍵字 hidebysig,我們可以忽略掉,方法簽名應(yīng)該看起來(lái)差不多。要了解到方法里主要發(fā)生了什么,你需要知道CIL把CPU看成一個(gè)堆棧式機(jī)器stack machine 而不是寄存器機(jī)器register machine。CIL假設(shè)CPU可以處理非常基礎(chǔ),非常算法的指令,例如”將兩個(gè)整數(shù)相加“,而且它可以處理任何內(nèi)存地址的隨機(jī)訪問(wèn)。CIL還假設(shè)CPU不直接在RAM上進(jìn)行算術(shù)操作,而是首先需要將數(shù)據(jù)裝載進(jìn)概念上的計(jì)算堆棧。(注意計(jì)算堆棧和你你知道的C#堆棧沒(méi)有任何關(guān)系。CIL計(jì)算堆棧只是一個(gè)抽象的,并且預(yù)設(shè)很小。)在行IL_0000到IL_0005發(fā)生了:

      • 兩個(gè)整型參數(shù)被推進(jìn)堆棧。
      • 加法被調(diào)用然后從堆棧里彈出開始位置的兩個(gè)對(duì)象,自動(dòng)將記過(guò)壓進(jìn)堆棧。
      • 第3和4行可以忽略,因?yàn)樵诎l(fā)行版本里會(huì)被優(yōu)化掉。
      • 這個(gè)方法返回堆棧的第一個(gè)值。

      找到CIL里面的內(nèi)存分配

      CIL代碼美在它不會(huì)隱藏任何堆分配。而且,堆分配會(huì)嚴(yán)格按照以下三個(gè)順序分配,在你的反匯編代碼里能看到。

      • newobj <constructor>:這創(chuàng)建了一個(gè)由constructor指定類型的未初始化的對(duì)象。如果這個(gè)對(duì)象是值類型,它就在堆棧上被創(chuàng)建。如果它是一個(gè)引用類型,就在堆上。你總是能從CIL代碼知道類型,所以你可以容易的知道內(nèi)存分配產(chǎn)生的地方。
      • newarr <element type>:這條指令在堆上創(chuàng)建了一個(gè)新的數(shù)組。Element的類型由參數(shù)指定。
      • box <value type token>:這條特殊的指令執(zhí)行裝箱操作,我們已經(jīng)在第一篇帖子里說(shuō)過(guò)。

      Let’s look at a rather contrived method that performs all three types of allocations.

      然我們來(lái)看一個(gè)人為的執(zhí)行這三種內(nèi)存分配的方法。

      1 void SomeMethod(){    
      2 object[] myArray = new object[1];    
      3 myArray[0] = 5;    
      4 Dictionary<int, int> myDict = new Dictionary<int, int>();
      5 myDict[4] = 6;    
      6 foreach (int key in myDict.Keys)    
      7 Console.WriteLine(key);
      8 }

      有這幾行代碼產(chǎn)生的CIL代碼很多,所以這里我們只看關(guān)鍵部分:

      IL_0001: newarr [mscorlib]System.Object…IL_000a: box [mscorlib]System.Int32…IL_0010: newobj instance void class [mscorlib]System.    Collections.Generic.Dictionary’2<int32, int32>::.ctor()…IL_001f: callvirt instance class [mscorlib]System.    Collections.Generic.Dictionary`2/KeyCollection<!0, !1>    class [mscorlib]System.Collections.Generic.Dictionary`2<int32,    int32>::get_Keys()

      正如我們懷疑過(guò)的,對(duì)象的數(shù)組(SomeMethod()里的第一行)導(dǎo)致newarr指令。整數(shù)5被賦給數(shù)組的第一個(gè)元素需要裝箱。Dictionary<int, int>是被newobj指令分配的。

      但是還有第四個(gè)堆分配!正如我在第一篇帖子里提到的,Dictionary<K, V>. KeyCollection被聲明為一個(gè)類,不是結(jié)構(gòu)。這個(gè)類的一個(gè)實(shí)例會(huì)被創(chuàng)建,這樣foreach蓄奴換才有迭代的對(duì)象。不幸的是,分配發(fā)生在Keys屬性的getter方法里。正如你在CIL代碼里看到,這個(gè)方法的名字是get_Keys(),而且它的返回值是一個(gè)類。

      作為一個(gè)查找內(nèi)存泄露的通用方法,你可以生成一個(gè)對(duì)你的整個(gè)程序集反匯編的CIL文件,只要在ILSpy按下Ctrl+S。然后用你喜歡的文本編輯器打開這個(gè)文件,搜索上面提到的三種指令。查出其他程序集里的內(nèi)存泄露是有難度。我唯一知道的辦法就是仔細(xì)檢查你的C#代碼,確認(rèn)所有的外部方法調(diào)用,并且一個(gè)個(gè)地查看它們的CIL代碼。你怎么知道什么時(shí)候就完成了?很簡(jiǎn)單:你的游戲可以流暢的運(yùn)行好幾個(gè)小時(shí),不因?yàn)槔占斐扇魏蔚男阅芷款i。

      PS:在之前的帖子里,我答應(yīng)要向你們展示如何確認(rèn)你們系統(tǒng)上的Mono版本。只要裝了ILSpy,沒(méi)有比這更簡(jiǎn)單的了。在ILSpy里,點(diǎn)擊打開然后找到Unity根目錄。找到Data/Mono/lib/mono/2.0然后打開mscorlib.dll。在層級(jí)視圖里,找到mscorlib/-/Consts,然后那兒你能找到MonoVersion作為一個(gè)字符串常量。

      轉(zhuǎn)自:http://www.cnblogs.com/yishansong/p/4344299.html

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多