都知道程式運行時的變數是放在記憶體里的,從我們學c++ 就知道有析構函數 malloc,還有學c#的時候天天 什麼垃圾回收 GC 像背八股文樣的 ,但是這個記憶體究竟能分配多少 沒有人想過吧 ,不論做什麼對未知的事充滿好奇永遠是前進發展的源泉,GC 怎樣才能體現GC的運作 今天我們就來實驗下吧。 首先初 ...
都知道程式運行時的變數是放在記憶體里的,從我們學c++ 就知道有析構函數 malloc,還有學c#的時候天天 什麼垃圾回收 GC 像背八股文樣的 ,但是這個記憶體究竟能分配多少 沒有人想過吧 ,不論做什麼對未知的事充滿好奇永遠是前進發展的源泉,GC 怎樣才能體現GC的運作 今天我們就來實驗下吧。
首先初級的知識還是啰嗦一下:
構造函數負責按照模板在記憶體中實例化對象,當然你類的這些附加變數都是放在一起的,那麼理所當然的我們就定義一個超大的數組來測試他。然後對應的~ClassName(){} 函數則在示例被銷毀的時候執行 也就是垃圾回收的時候。於是乎有了下麵這段代碼:
1 public class Class3 2 { 3 public string Name { get; set; } 4 public int[] ar = null; 5 public Class3(string _name) 6 { 7 Name = _name; 8 9 ar = new int[20000000]; 10 Console.WriteLine("my name is :" + Name); 11 } 12 13 14 15 ~Class3() 16 { 17 Console.WriteLine("GC working:" + Name); 18 } 19 }
按照我們正常人的理解,以及以往C++的經驗。你一個方法執行 執行完畢 所有花括弧內的自動變數都會被銷毀。但是new出來的東西確不一樣屬於malloc空間的 放在堆上 ,如果沒有hold住地址就不能進行有效記憶體控制 進而就成了野指針 記憶體泄露。但是 我說但是 按照我們一個神經正常的人理解 你要自動化的處理這個事情 你會怎麼做?你對象new完 放那 總要有一個東西在運行時就像一絲線一樣一直把他掛著掛著的 ,沒有東西把他掛著可不就代表這對象沒用了麽。我們建一個winform程式,按鈕事件里先寫段代碼:
1 Random rdm = new Random(); 2 Class3 c1 =new Class3(rdm.Next().ToString()); 3 4 c1 = null; 5 GC.Collect();
網上說這裡做了c1=null後 立即就會觸發回收,純屬是扯淡,這個完全是未知的, 但是調用GC.Collect()呢基本上呢確實至多第二次就會觸發回收。但是如果我沒把GC.Collect()去掉呢讓其發展呢,這就要看心情了,有時候很久都不會有什麼動作c1=null這句要不要都一樣。根據數組大小我這邊的運行情況基本上存儲4組大概76M就會進行回收。如果有引用把對象掛著呢,當然 就不會進行回收,那麼最大可以存多少呢?我這邊特意把配置設為32位的情況下大概1.14Gb的時候就會溢出。
1 int cliCount = 0; 2 List<Class3> clist = new List<Class3>(); 3 4 private void button1_Click(object sender, EventArgs e) 5 { 6 Random rdm = new Random(); 7 8 Class3 c3 = new Class3(rdm.Next().ToString()); 9 cliCount++; 10 Console.WriteLine("count:"+cliCount.ToString() ); 11 clist.Add(c3); 12 }
如果是x64則上不封頂,註意 記憶體的增長體現在紅框處,滿了後會自動繼續擴,會超出實際物理記憶體。由於Windows系統是虛擬記憶體機制,內部進行了一些玄妙的處理咱也不瞭解。不管咋樣對應程式來說當成正常區域訪問。
通過上面的測試可以驗證垃圾回收的機制基本上還是按照我們常規理解的套路去運作的的。 C++ 的時候要很謹慎 一層一層的 調用了new 一定別忘了delete 然後析構函數里也是一樣。C#里把好多記憶體分配相關的弱化了 感覺析構函數差不多成擺設了。