2013年7月31日 星期三

VB.NET 變數Value & Reference 探討記憶體交換

本文章 簡單易懂 我就一字不漏剪下貼上拉
本文出處


蠻有趣的議題 ...(我個人認為啦)
相信大家都知道 ...在新版本的高階語言
有關於 Reference 型態的變數 String Array Decimal
String 字串 都是不可改變的
所以 再做連結、更改字串的動作是非常的耗費記憶體 ...
怎麼說呢 ... 簡單來講好了

1 Dim s as String = "測試用文字"
2 s += "新增的文字"
非常簡單的兩行
學問可大了 ...
首先 .NET 會跟Windows老大要一個 記憶體空間
Windows 會給.NET一段記憶體位址 (0x????????) 的記憶體堆疊位址(heap) 代號為 s(基本上學 C++的會比較懂這個)
然後 把"測試用文字" 放到這段 記憶體位址裡面(一字2Byte 所以總共佔了10Byte
s所儲存的 是 (假設 0x2c000001) 而不是直接儲存文字
第二行相信大家都沒有問題 ... 把s 原本的值 在接上 "新增的文字" 這五個字 結果會是 "測試用文字新增的文字"
可是 這背後 .NET 到底做了什麼呢!? ..
由於新版高階語言的規定,字串是不得改變的
所以 再做字串連結的時候 .NET 會先要一段記憶體 來存放 "新增的文字" (10Byte)(假設是 0x7a010368)
然後 再把兩個字串做連結 ... 由於字串不得改變的原理 ...
.NET 會在要另一個記憶體位址 (假設0x99asd217) 再把上面 "測試用文字新增的文字" 放到這個記憶體位址裡面(20Byte)
然後 再把 0x99asd217 給 s
光是做一個這麼簡單的動作 ... 總共就使用了40Byte 而且在40Byte裡面還有 20Byte 的記憶體是浪費掉的 ...
如果有興趣做實驗 以下有個小小的試驗 ...

1 Dim Watch As New Stopwatch
2 Watch.Start()
3 Dim s As String = ""
4 For x As Integer = 0 To 100000
5 s += x.ToString() & Environment.NewLine()
6 Next
7 Watch.Stop()
8 Dim i As Integer = Watch.ElapsedMilliseconds / 1000
9 Watch.Reset()
做 10萬字 連字串 ...
基本上 測試過 至少都要1分鐘左右以上電腦比較慢的 甚至要到5分鐘 ...
而且 在工作管理員裡面 會發現 實體記憶體慢慢的再被吃掉 ...
好了 以上只是一個小小的測試 ...
基於上面這個原理 ...
來看我們下面的例子
1 Dim s1 As String = "測試用文字"
2 Dim s2 As String
3 s2 = s1
4 s2 = "新增的文字"

這段程式 執行出來之後 ... s1 和 s2 各會是多少呢?
別急 先想一想再看答案 ...
答案

神奇嗎...
再來一個更神奇的 ..
1 Dim i As Integer() = New Integer() {90, 80, 70, 60, 50}
2 Dim j As Integer()
3 j = i
4 j(0) = 10
5 j(1) = 20

執行的結果是什麼呢 ??
i 陣列 五個值是多少? j陣列 五個值是多少?
一樣 先思考一下 再看答案囉 ...
答案
再來 用 Value 型態的
value 型態的變數 如 Integer Char Byte 等等 ...
是直接儲存再記憶體data.bss 而不是heap
所以 在我們宣告以下
1 Dim i As Integer = 10
2 Dim j As Integer
3 j = i
4 j = 20

這邊 應該不難理解 ...
i 出來會是 10
j 出來 會是 20
因為 他們都是再同一個記憶體區段 ...
第三行 j = i 是把 i的值(10) Copy 給 j
所以 記憶體內 有 i = 10 , j = 10
再來 我把 j 指定為 20
就變成了 i = 10 , j = 20 是 不會互相引響的~
以上 ...
Phoenix 8/7
DotBlogs Tags: .NET

沒有留言:

張貼留言