堆棧是什麼?html
在說堆棧以前,先說說內存是神馬?程序員
內存:程序在運行的過程,電腦須要不斷經過CPU進行計算,這個計算的過程會讀取併產生運算的數據,這些數據須要一個存儲容器存放。這個容器,這就是內存了。算法
咱們知道C#是強類型語言,每一個變量和常量都有一個類型,即全部的數據都會有一個類型。在.Net中,全部的類型又分爲值類型和引用類型。簡單介紹一下。數據結構
值類型:使用int,float,struct,enum關鍵字直接繼承自System.ValueType定義的類型。app
引用類型:Class,interface,string,delegate繼承自System.Object。大數據
值類型和引用類型有什麼區別吶?優化
主要區別在於值類型對象固定大小,引用類型對象能夠指向任何類型,沒法肯定其大小。所以內存區域分爲棧和堆。值類型存儲在棧上,引用類型存儲在堆上。spa
棧:操做系統會爲每條線程分配必定的空間,Windows爲1M。在棧上的成員不受GC管理器的控制,直接由操做系統分配。或者理解爲存儲短時間較小數據塊,超出做用域,自動釋放。操作系統
堆:主要用來存放引用類型對象,不須要咱們人工去分配和釋放,由GC管理器託管。或者理解爲存儲長期較大數據塊,超出做用域並不會被釋放,保持被分配的狀態。GC會處理未引用的堆內存。線程
不一樣於值類型直接在棧中存放值,引用類型還須要在棧中存放一個指向堆中對象的值的地址。
值類型,引用類型區別詳見:https://www.cnblogs.com/u3ddjw/p/6756536.html
值類型和引用類型之間能夠互轉嗎?
這個需求,是很常見,因此要說一下。答案是確定的,固然能夠,這裏就須要提到裝箱(值類型===>引用類型),拆箱(引用類型===>值類型)。
裝箱:
I.分配堆內存
II.將值類型的實例字段拷貝到新分配的堆內存中
III.返回託管堆中新分配的對象的地址在棧中。這個地址就是一個指向對象的引用。
拆箱:
I.檢查對象實例,確保它是給定值類型的一個裝箱值。
II.將該值實例複製到值類型變量中。
①GC和堆內存聯繫
上述說到棧是操做系統實時自動分配釋放,不須要咱們去管理。堆內存也是由GC控制管理。可是GC並非實時管理的,是須要經過程序員手動或系統定時觸發的。由於GC是一個耗時的操做,可能在有些系統中觸發的不合時宜(明顯卡頓)。因此,GC也須要優化,須要控制在合事宜的狀況觸發。好比遊戲中咱們須要在切換Loading時觸發GC,而在遊戲戰鬥中控制不能被觸發。
所以優化GC,就是優化堆內存,就是儘可能減小堆內存,及時回收堆內存。
②GC是什麼?
GC即(Gabarage Collector,垃圾回收器),歸屬於CLR(公共語言運行時,能夠理解爲.Net虛擬機),專門用於回收託管堆內存的
③GC如何釋放堆內存的?
GC清理堆時,GC收集器會經過必定的算法清理堆中的對象,而且版本不一樣算法也不一樣。標記-壓縮算法:經過一個圖的數據結構來收集對象的根,這個根就是引用地址。能夠理解爲指向託管堆的關係線。當觸發這個算法時,會檢查圖中的每一個根是否可達,若是可達,則對其標記,而後在堆上找到剩餘沒有標記的對象進行刪除,這樣,
那些再也不使用的堆中對象就刪除了。
爲了優化內存結構,減小在圖中搜索的成本,GC機制又爲每一個託管堆對象定義了一個屬性,將每一個對象分爲三個等級,0代,1代,2代。
每當new一個對象的時候,該對象會被定義爲第0代,當GC開始回收的時候,先從第0代開始,在這樣一次回收動做以後,0代沒有被回收的對象則被定義爲第1代,當回收第1代的時候,第1代中沒有被清理的對象會被定義爲第2代。
CLR會爲0/1/2代選擇一個預算的容量,0代一般爲256k-4mb預算,1代爲512-4m,2代不受限制,最大可擴充至操做系統的整個內存空間。代數越長說明這個對象經歷了回收的次數越多,那就意味着該對象是最不容易被清除的。這種分代的思想將對象分割成新老對象,進而配對不一樣的清除條件,這種巧妙的思想避免了直接清理整個堆(卡頓後果)。
擴展說明:
好比Unity採用貝姆垃圾回收機制與.Net垃圾回收器相比一直有很大的限制。
I.貝姆垃圾回收:無分代\並行,執行時全部線程阻塞;每次標記都會訪問全部可達的對象(窮舉搜索垃圾)。這種方式極有可能在短期形成幀率降低,影響玩家體驗。
II.分代回收:效率高不少。
參考:https://1996v.cnblogs.com/p/9037603.html?from=timeline&isappinstalled=0