成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

用 Span 對 C# 進程中三大內存區域進行統一訪問 ,太厲害了!

存儲 存儲軟件 后端
總的來說,這一篇主要是從思想上帶大家一起認識 Span,以及如何用 Span 對接 三大區域內存,關于 Span 的好處以及源碼解析。

[[348727]]

 一:背景

1. 講故事

前段時間寫了幾篇 C# 漫文,評論留言中有很多朋友多次提到 Span,周末抽空看了下,確實是一個非常的新結構,讓我想到了當年的WCF,它統一了.NET下各種零散的分布式技術,包括:.NET Remoteing,WebService,NamedPipe,MSMQ,而這里的 Span 統一了 C# 進程中的三大塊內存訪問,包括:棧內存, 托管堆內存, 非托管堆內存,畫個圖如下:

 

接下來就和大家具體聊聊這三大塊的內存統一訪問。

二:進程中的三大塊內存解析

1. 棧內存

大家應該知道方法內的局部變量是存放在棧上的,而且每一個線程默認會被分配 1M 的內存空間,我舉個例子:

  1. static void Main(string[] args) 
  2.         { 
  3.             int i = 10; 
  4.             long j = 20; 
  5.             List<string> list = new List<string>(); 
  6.         } 

上面 i,j 的值都是存于棧上,list的堆上內存地址也是存于棧上,為了看個究竟,可以用 windbg 驗證一下:

  1. 0:000> !clrstack -l 
  2. OS Thread Id: 0x2708 (0) 
  3.         Child SP               IP Call Site 
  4. 00000072E47CE558 00007ff89cf7c184 [InlinedCallFrame: 00000072e47ce558] Interop+Kernel32.ReadFile(IntPtr, Byte*, Int32, Int32 ByRef, IntPtr) 
  5. 00000072E47CE558 00007ff7c7c03fd8 [InlinedCallFrame: 00000072e47ce558] Interop+Kernel32.ReadFile(IntPtr, Byte*, Int32, Int32 ByRef, IntPtr) 
  6. 00000072E47CE520 00007FF7C7C03FD8 ILStubClass.IL_STUB_PInvoke(IntPtr, Byte*, Int32, Int32 ByRef, IntPtr) 
  7. 00000072E47CE7B0 00007FF8541E530D System.Console.ReadLine() 
  8. 00000072E47CE7E0 00007FF7C7C0101E DataStruct.Program.Main(System.String[]) [E:\net5\ConsoleApp2\ConsoleApp1\Program.cs @ 22] 
  9.     LOCALS: 
  10.         0x00000072E47CE82C = 0x000000000000000a 
  11.         0x00000072E47CE820 = 0x0000000000000014 
  12.         0x00000072E47CE818 = 0x0000018015aeab10 

通過 clrstack -l 查看線程棧,最后三行可以明顯的看到 0a -> 10, 14 -> 20 , 0xxxxxxb10 => list堆地址,除了這些簡單類型,還可以在棧上分配復雜類型,這里就要用到 stackalloc 關鍵詞, 如下代碼:

  1. int* ptr = stackalloc int[3] { 10, 11, 12 }; 

問題就在這里,指針類型雖然靈活,但是做任何事情都比較繁瑣,比如說:

  • 查找某一個數是否在 int[] 中
  • 反轉 int[]
  • 剔除尾部的某一個數字(比如 12)

就拿第一個問題來說,操作指針的代碼如下:

  1. //指針接收 
  2.             int* ptr = stackalloc int[3] { 10, 11, 12 }; 
  3.  
  4.             //包含判斷 
  5.             for (int i = 0; i < 3; i++) 
  6.             { 
  7.                 if (*ptr++ == 11) 
  8.                 { 
  9.                     Console.WriteLine(" 11 存在 數組中"); 
  10.                 } 
  11.             } 

 

后面的兩個問題就更加復雜了,既然 Span 是統一訪問,就應該用 Span 來接 stackalloc,代碼如下:

  1. Span<int> span = stackalloc int[3] { 10, 11, 12 }; 
  2.  
  3.             //1. 是否包含 
  4.             var hasNum = span.Contains(11); 
  5.  
  6.             //2. 反轉 
  7.             span.Reverse(); 
  8.  
  9.             //3. 剔除尾部 
  10.             span.Trim(12); 

這就很了,你既不需要接觸指針,又能完成指針的大部分操作,而且還特別便捷,佩服,最后來驗證一下 int[] 是否真的在 線程棧 上。

  1. 0:000> !clrstack -l 
  2. 000000ED7737E4B0 00007FF7C4EA16AD DataStruct.Program.Main(System.String[]) [E:\net5\ConsoleApp2\ConsoleApp1\Program.cs @ 28] 
  3.     LOCALS: 
  4.         0x000000ED7737E570 = 0x000000ed7737e4d0 
  5.         0x000000ED7737E56C = 0x0000000000000001 
  6.         0x000000ED7737E558 = 0x000000ed7737e4d0 
  7.  
  8. 0:000> dp 0x000000ed7737e4d0 
  9. 000000ed`7737e4d0  0000000b`0000000c 00000000`0000000a 

從 Locals 處的 0x000000ED7737E570 = 0x000000ed7737e4d0 可以看到 key / value 是非常相近的,說明在棧上無疑。

從最后一行 a,b,c 可看出對應的就是數組中的 10,11,12。

2. 非托管堆內存

說到非托管內存,讓我想起了當年 C# 調用 C++ 的場景,代碼到處充斥著類似下面的語句:

  1. private bool SendMessage(int messageType, string ip, string port, int length, byte[] messageBytes) 
  2.         { 
  3.             bool result = false
  4.             if (windowHandle != 0) 
  5.             { 
  6.                 var bytes = new byte[Const.MaxLengthOfBuffer]; 
  7.                 Array.Copy(messageBytes, bytes, messageBytes.Length); 
  8.  
  9.                 int sizeOfType = Marshal.SizeOf(typeof(StClientData)); 
  10.  
  11.                 StClientData stData = new StClientData 
  12.                 { 
  13.                     Ip = GlobalConvert.IpAddressToUInt32(IPAddress.Parse(ip)), 
  14.                     Port = Convert.ToInt16(port), 
  15.                     Length = Convert.ToUInt32(length), 
  16.                     Buffer = bytes 
  17.                 }; 
  18.  
  19.  
  20.                 int sizeOfStData = Marshal.SizeOf(stData); 
  21.  
  22.                 IntPtr pointer = Marshal.AllocHGlobal(sizeOfStData); 
  23.  
  24.                 Marshal.StructureToPtr(stData, pointer, true); 
  25.  
  26.                 CopyData copyData = new CopyData 
  27.                 { 
  28.                     DwData = (IntPtr)messageType, 
  29.                     CbData = Marshal.SizeOf(sizeOfType), 
  30.                     LpData = pointer 
  31.                 }; 
  32.  
  33.                 SendMessage(windowHandle, WmCopydata, 0, ref copyData); 
  34.  
  35.                 Marshal.FreeHGlobal(pointer); 
  36.  
  37.                 string data = GlobalConvert.ByteArrayToHexString(messageBytes); 
  38.                 CommunicationManager.Instance.SendDebugInfo(new DataSendEventArgs() { Data = data }); 
  39.  
  40.                 result = true
  41.             } 
  42.             return result; 
  43.         } 

上面代碼中的: IntPtr pointer = Marshal.AllocHGlobal(sizeOfStData); 和 Marshal.FreeHGlobal(pointer) 就用到了非托管內存,從現在開始你就可以用 Span 來接 Marshal.AllocHGlobal 分配的非托管內存啦!,如下代碼所示:

  1. class Program 
  2.     { 
  3.         static unsafe void Main(string[] args) 
  4.         { 
  5.             var ptr = Marshal.AllocHGlobal(3); 
  6.  
  7.             //將 ptr 轉換為 span 
  8.             var span = new Span<byte>((byte*)ptr, 3) { [0] = 10, [1] = 11, [2] = 12 }; 
  9.  
  10.             //然后在  span 中可以進行各種操作了。。。 
  11.  
  12.             Marshal.FreeHGlobal(ptr); 
  13.         } 
  14.     } 

這里我也用 windbg 給大家看一下 未托管內存 在內存中是個什么樣子。

  1. 0:000> !clrstack -l 
  2. OS Thread Id: 0x3b10 (0) 
  3.         Child SP               IP Call Site 
  4. 000000A51777E758 00007ff89cf7c184 [InlinedCallFrame: 000000a51777e758] Interop+Kernel32.ReadFile(IntPtr, Byte*, Int32, Int32 ByRef, IntPtr) 
  5. 000000A51777E758 00007ff7c4654dd8 [InlinedCallFrame: 000000a51777e758] Interop+Kernel32.ReadFile(IntPtr, Byte*, Int32, Int32 ByRef, IntPtr) 
  6. 000000A51777E720 00007FF7C4654DD8 ILStubClass.IL_STUB_PInvoke(IntPtr, Byte*, Int32, Int32 ByRef, IntPtr) 
  7. 000000A51777E9E0 00007FF7C46511D0 DataStruct.Program.Main(System.String[]) [E:\net5\ConsoleApp2\ConsoleApp1\Program.cs @ 26] 
  8.     LOCALS: 
  9.         0x000000A51777EA58 = 0x0000027490144760 
  10.         0x000000A51777EA48 = 0x0000027490144760 
  11.         0x000000A51777EA38 = 0x0000027490144760 
  12.  
  13. 0:000> dp 0x0000027490144760 
  14. 00000274`90144760  abababab`ab0c0b0a abababab`abababab         

最后一行的 0c0b0a 這就是低位到高位的 10,11,12 三個數,接下來從 Locals 處 0x000000A51777EA58 = 0x0000027490144760 可以看出,這個key,value 相隔十萬八千里,說明肯定不在棧內存中,繼續用 windbg 鑒別一下 0x0000027490144760 是否是托管堆上,可以用 !eeheap -gc 查看托管堆地址范圍,如下代碼:

  1. 0:000> !eeheap -gc 
  2. Number of GC Heaps: 1 
  3. generation 0 starts at 0x00000274901B1030 
  4. generation 1 starts at 0x00000274901B1018 
  5. generation 2 starts at 0x00000274901B1000 
  6. ephemeral segment allocation context: none 
  7.          segment             begin         allocated              size 
  8. 00000274901B0000  00000274901B1000  00000274901C5370  0x14370(82800) 
  9. Large object heap starts at 0x00000274A01B1000 
  10.          segment             begin         allocated              size 
  11. 00000274A01B0000  00000274A01B1000  00000274A01B5480  0x4480(17536) 
  12. Total Size:              Size: 0x187f0 (100336) bytes. 
  13. ------------------------------ 
  14. GC Heap Size:    Size: 0x187f0 (100336) bytes. 

從上面信息可以看到,0x0000027490144760 明顯不在:3代堆:00000274901B1000 ~ 00000274901C5370 和 大對象堆:00000274A01B1000 ~ 00000274A01B5480 區間范圍內。

3. 托管堆內存

用 Span 統一托管內存訪問那是相當簡單了,如下代碼所示:

Span span = new byte[3] { 10, 11, 12 };

同樣,你有了Span,你就可以使用 Span 自帶的各種方法,這里就不多介紹了,大家有興趣可以實操一下。

三:總結

總的來說,這一篇主要是從思想上帶大家一起認識 Span,以及如何用 Span 對接 三大區域內存,關于 Span 的好處以及源碼解析,后面上專門的文章吧!

本文轉載自微信公眾號「 一線碼農聊技術」,可以通過以下二維碼關注。轉載本文請聯系 一線碼農聊技術公眾號。

 

 

責任編輯:武曉燕 來源: 一線碼農聊技術
相關推薦

2021-11-01 07:50:44

TomcatWeb應用

2022-06-06 07:52:00

Python大風車

2021-10-08 13:38:23

手機系統鴻蒙

2022-04-08 08:11:28

Python代碼

2018-04-11 14:30:33

2017-02-23 08:00:04

智能語音Click

2023-03-03 09:11:55

軟件開發NASA

2018-05-14 22:58:14

戴爾

2021-03-01 12:06:12

Nginx命令Linux

2011-06-21 11:16:24

cc++

2011-04-13 16:50:54

CC++內存

2025-01-09 11:10:15

2023-05-06 06:47:46

Bing聊天機器人

2023-09-08 09:12:57

內存緩存圖像

2024-02-26 13:47:00

C#Socket數據接收

2024-02-26 12:42:40

2019-02-12 11:07:49

2023-11-01 08:07:42

.NETC#
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 中文字幕视频一区 | www.av在线 | 久久国产精品免费一区二区三区 | 国产日韩精品在线 | 国产精品久久久久久久久久免费 | 国产免费观看视频 | 91激情电影 | 国产精品a久久久久 | 免费观看一级特黄欧美大片 | 欧美一级免费看 | 欧美精品一区二区三区在线播放 | 日韩美香港a一级毛片免费 国产综合av | 亚洲视频一区在线播放 | 成人免费视频播放 | 欧美激情精品久久久久 | 精品成人在线视频 | 成人亚洲网 | 99草免费视频 | 欧美一区二区在线视频 | 黄色一级大片在线免费看产 | 午夜视频在线播放 | 国产免费视频 | 国产精品爱久久久久久久 | 久久国产精品一区二区三区 | 亚洲精品在线看 | 久久夜视频 | 国产精品国产三级国产aⅴ中文 | 激情一区二区三区 | 国产精品久久久久久久7电影 | 人人干人人草 | 亚洲精品高清视频 | 成人久久久久 | 成人不卡 | 国产精品日产欧美久久久久 | 日韩久草| 免费九九视频 | 亚洲成av人片在线观看无码 | 一级黄色片毛片 | 国产亚洲精品久久午夜玫瑰园 | 国产视频精品免费 | 一区二区三区免费 |