c#压缩字符串的方法

2020-06-24 18:02:36王冬梅

接下来只需要在tradefrom 字段包一层 string.Intern 即可,改动不要太小,代码如下:

 static void Main(string[] args)
 {
  var trades = Enumerable.Range(0, 20 * 10000).Select(m => new Trade()
  {
  TradeID = m,
  TradeFrom = string.Intern(File.ReadLines(Environment.CurrentDirectory + "//orderfrom.txt")
     .ElementAt(m % 4)), //包一层 string.Intern
  }).ToList();

  GC.Collect(); //方便测试,把临时变量清掉
  Console.WriteLine("执行成功");
  Console.ReadLine();
 }

然后用windbg抓一下托管堆。

0:000> !dumpheap -stat 
Statistics:
  MT Count TotalSize Class Name
00007ff9eb2b59c0 204 10386 System.String

0:000> !clrstack -l
OS Thread Id: 0x13f0 (0)
 Child SP  IP Call Site

ConsoleApp6.Program.Main(System.String[]) [C:dreamCsharpConsoleApp1ConsoleApp6Program.cs @ 27]
 LOCALS:
 0x0000005e4d3ff0a8 = 0x000001f8a15129a8

0000005e4d3ff2b8 00007ff9ecd96c93 [GCFrame: 0000005e4d3ff2b8] 
0:000> !objsize 0x000001f8a15129a8
sizeof(000001f8a15129a8) = 8497368 (0x81a8d8) bytes (System.Collections.Generic.List`1[[ConsoleApp6.Trade, ConsoleApp6]])

观察后发现,当用了驻留池之后空间为: 8497368 /1024/1024 =8.1M,你可能有疑问,为什么和字典化相比内存要大24%呢? 仔细观察你会发现,当用驻留池后,List<Trade> 中的TradeFrom存的是string在堆中的内存地址,在x64机器上要占用8个字节,而字典化方式内存堆上Trade是不分配TradeFrom,而是用了一个byte来替代,总体来说相当于一个trade省了7byte的空间,然后用windbg看一下。

0:000> !da -length 1 -details 000001f8b16f9b68
Name: ConsoleApp6.Trade[]
Size: 2097176(0x200018) bytes
Array: Rank 1, Number of elements 262144, Type CLASS

 Fields:
   MT Field Offset   Type VT Attr  Value Name
 00007ff9eb2b85a0 4000001 10  System.Int32 1 instance   0 <TradeID>k__BackingField
 00007ff9eb2b59c0 4000002 8  System.String 0 instance 000001f8a1516030 <TradeFrom>k__BackingField

0:000> !DumpObj /d 000001f8a1516030
Name: System.String
String: WAP

可以看到, 000001f8a1516030 就是 堆上 string=Wap的引用地址,这个地址占用了8byte空间。

再回头dump一下使用字典化方式的Trade,可以看到它是没有 <TradeFrom>k__BackingField 字段的。

0:000> !da -length 1 -details 000001ed52759ac0
Name: ConsoleApp6.Trade[]
Size: 262168(0x40018) bytes
Array: Rank 1, Number of elements 32768, Type CLASS
 Fields:
   MT Field Offset   Type VT Attr  Value Name
 00007ff9eb2b85a0 4000002 8  System.Int32 1 instance   0 <TradeID>k__BackingField
 00007ff9eb2b7d20 4000003 c  System.Byte 1 instance   0 <TradeFromID>k__BackingField

三:总结

大家可以根据自己的情况使用,使用驻留池方式是改变最小的,简单粗暴,自己构建字典化虽然最省内存,但需要修正业务逻辑,这个风险自担哦。。。