最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

c#壓縮字符串的方法

 更新時(shí)間:2020年06月24日 14:34:08   作者:一線碼農(nóng)  
這篇文章主要介紹了c#壓縮字符串的方法,文中示例代碼非常詳細(xì),供大家參考和學(xué)習(xí),感興趣的朋友可以了解下

一:背景

1. 講故事

在我們的一個(gè)全內(nèi)存項(xiàng)目中,需要將一家大品牌店鋪小千萬的trade灌入到內(nèi)存中,大家知道trade中一般會有訂單來源,省市區(qū) ,當(dāng)把這些字段灌進(jìn)去后,你會發(fā)現(xiàn)他們特別侵蝕內(nèi)存,因?yàn)槎际亲址愋?,不知道大家對?nèi)存侵蝕性是不是很清楚,我就問一個(gè)問題。

Question: 一個(gè)空字符串占用多大內(nèi)存? 你知道嗎?

思考之后,下面我們就一起驗(yàn)證下,使用windbg去托管堆一查究竟,代碼如下:

 static void Main(string[] args)
 {
  string s = string.Empty;

  Console.ReadLine();
 }

0:000> !clrstack -l
OS Thread Id: 0x308c (0)
 Child SP  IP Call Site
ConsoleApp6.Program.Main(System.String[]) [C:\dream\Csharp\ConsoleApp1\ConsoleApp6\Program.cs @ 19]
 LOCALS:
 0x00000087391febd8 = 0x000002605da91420
0:000> !DumpObj /d 000002605da91420
Name: System.String
String: 
Fields:
  MT Field Offset   Type VT Attr  Value Name
00007ff9eb2b85a0 4000281 8  System.Int32 1 instance  0 m_stringLength
00007ff9eb2b6838 4000282 c  System.Char 1 instance  0 m_firstChar
00007ff9eb2b59c0 4000286 d8 System.String 0 shared  static Empty
     >> Domain:Value 000002605beb2230:NotInit <<
0:000> !objsize 000002605da91420
sizeof(000002605da91420) = 32 (0x20) bytes (System.String)

從圖中你可以看到,僅僅一個(gè)空字符串就要占用 32byte,如果500w個(gè)空字符串就是: 32byte x 500w = 152M,是不是不算不知道,一算嚇一跳。。。 這還僅僅是一個(gè)什么都沒有的空字符串哦。

2. 回歸到Trade

問題也已經(jīng)擺出來了,接下來回歸到Trade中,為了方便演示,先模擬以文件的形式從數(shù)據(jù)庫讀取20w的trade。

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

  GC.Collect(); //方便測試,把臨時(shí)變量清掉
  Console.WriteLine("執(zhí)行成功");
  Console.ReadLine();
 }
 }

 class Trade
 {
 public int TradeID { get; set; }
 public string TradeFrom { get; set; }
 }

然后用windbg去跑一下托管堆,再量一下trades的大小。

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

0:000> !objsize 0x000001a5860629a8
sizeof(000001a5860629a8) = 16097216 (0xf59fc0) bytes (System.Collections.Generic.List`1[[ConsoleApp6.Trade, ConsoleApp6]])

從上面輸出中可以看到托管堆有200200 = 20w(程序分配)+ 200(系統(tǒng)分配)個(gè),然后再看size: 16097216/1024/1024= 15.35M,這就是展示的所有原始情況。

二:壓縮技巧分析

1. 使用字典化處理

其實(shí)在托管堆上有20w個(gè)字符串,但你仔細(xì)觀察一下會發(fā)現(xiàn)其實(shí)就是4種狀態(tài)的重復(fù)顯示,要么一淘,要么淘寶。。。這就給了我優(yōu)化機(jī)會,何不在獲取數(shù)據(jù)的時(shí)候構(gòu)建好OrderFrom的字典,然后在trade中附增一個(gè)TradeFromID記錄字典中的映射值,因?yàn)樘卣髦瞪伲胋yte就可以了,有了這個(gè)思想,可以把代碼修改如下:

 class Program
 {
 public static Dictionary<int, string> orderfromDict = new Dictionary<int, string>();

 static void Main(string[] args)
 {
  var trades = Enumerable.Range(0, 20 * 10000).Select(m =>
  {
  var tradefrom = File.ReadLines(Environment.CurrentDirectory + "http://orderfrom.txt")
     .ElementAt(m % 4);

  var kv = orderfromDict.FirstOrDefault(k => k.Value == tradefrom);

  if (kv.Key == 0)
  {
   orderfromDict.Add(orderfromDict.Count + 1, tradefrom);
  }

  var trade = new Trade() { TradeID = m, TradeFromID = (byte)kv.Key };

  return trade;

  }).ToList();

  GC.Collect(); //方便測試,把臨時(shí)變量清掉

  Console.WriteLine("執(zhí)行成功");

  Console.ReadLine();
 }
 }

 class Trade
 {
 public int TradeID { get; set; }

 public byte TradeFromID { get; set; }

 public string TradeFrom
 {
  get
  {
  return Program.orderfromDict[TradeFromID];
  }
 }
 }

代碼還是很簡單的,接下來用windbg看一下空間到底壓縮了多少?

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

0:000> !clrstack -l
OS Thread Id: 0x2ce4 (0)
 Child SP  IP Call Site
ConsoleApp6.Program.Main(System.String[]) [C:\dream\Csharp\ConsoleApp1\ConsoleApp6\Program.cs @ 42]
 LOCALS:
 0x0000006f4d9ff078 = 0x0000016fdcf82ab8

0000006f4d9ff288 00007ff9ecd96c93 [GCFrame: 0000006f4d9ff288] 
0:000> !objsize 0x0000016fdcf82ab8
sizeof(0000016fdcf82ab8) = 6897216 (0x693e40) bytes (System.Collections.Generic.List`1[[ConsoleApp6.Trade, ConsoleApp6]])

從上面的輸出中可以看到,托管堆上string現(xiàn)在是:204 = 4(程序分配) + 200(系統(tǒng)分配)個(gè),這4個(gè)就是字典中的4個(gè)哦,空間的話:6897216 /1024/1024= 6.57M,對應(yīng)之前的 15.35M優(yōu)化了將近60%。

雖然優(yōu)化了60%,但這種優(yōu)化是破壞性的優(yōu)化,需要修改我的Trade結(jié)構(gòu),同時(shí)還要定義個(gè)Dictionary,而且還有不小幅度的修改業(yè)務(wù)邏輯,大家都知道線上的代碼是能不改則不改,不改肯定沒錯(cuò),改出問題肯定是你兜著走,是吧,那問題就來了,如何最小化的修改而且還能壓縮空間,有這樣兩全其美的事情嗎???

2. 利用字符串駐留池

貌似一說出來,大家都如夢初醒,駐留池的出現(xiàn)就是為了解決這個(gè)問題,CLR會在內(nèi)部維護(hù)了一個(gè)我剛才定義的字典機(jī)制,重復(fù)的字符串就不需要在堆上再次分配,直接存它的引用地址即可,如果你不清楚駐留池,建議看一下我這篇: http://www.fzitv.net/article/189450.htm

接下來只需要在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 + "http://orderfrom.txt")
     .ElementAt(m % 4)), //包一層 string.Intern
  }).ToList();

  GC.Collect(); //方便測試,把臨時(shí)變量清掉
  Console.WriteLine("執(zhí)行成功");
  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:\dream\Csharp\ConsoleApp1\ConsoleApp6\Program.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]])

觀察后發(fā)現(xiàn),當(dāng)用了駐留池之后空間為: 8497368 /1024/1024 =8.1M,你可能有疑問,為什么和字典化相比內(nèi)存要大24%呢? 仔細(xì)觀察你會發(fā)現(xiàn),當(dāng)用駐留池后,List<Trade> 中的TradeFrom存的是string在堆中的內(nèi)存地址,在x64機(jī)器上要占用8個(gè)字節(jié),而字典化方式內(nèi)存堆上Trade是不分配TradeFrom,而是用了一個(gè)byte來替代,總體來說相當(dāng)于一個(gè)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的引用地址,這個(gè)地址占用了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

三:總結(jié)

大家可以根據(jù)自己的情況使用,使用駐留池方式是改變最小的,簡單粗暴,自己構(gòu)建字典化雖然最省內(nèi)存,但需要修正業(yè)務(wù)邏輯,這個(gè)風(fēng)險(xiǎn)自擔(dān)哦。。。

以上就是c#壓縮字符串的方法的詳細(xì)內(nèi)容,更多關(guān)于c#壓縮字符串的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 詳解C#中yield關(guān)鍵字的用法

    詳解C#中yield關(guān)鍵字的用法

    yield?關(guān)鍵字的用途是把指令推遲到程序?qū)嶋H需要的時(shí)候再執(zhí)行,這個(gè)特性允許我們更細(xì)致地控制集合每個(gè)元素產(chǎn)生的時(shí)機(jī),那么下面就一起來看下怎么用?yield?關(guān)鍵字吧
    2023-07-07
  • c#求兩個(gè)數(shù)中最大值的方法

    c#求兩個(gè)數(shù)中最大值的方法

    這篇文章主要介紹了c#求兩個(gè)數(shù)中最大值的方法,需要的朋友可以參考下
    2014-02-02
  • 在.NET?WebService中跨域CORS問題的解決方案

    在.NET?WebService中跨域CORS問題的解決方案

    在現(xiàn)代的Web應(yīng)用程序開發(fā)中,跨域資源共享(Cross-Origin?Resource?Sharing,?CORS)問題是開發(fā)者經(jīng)常遇到的一個(gè)挑戰(zhàn),在這篇博客中,我們將深入探討如何在?.NET?WebService?中解決CORS問題,幫助開發(fā)者順利實(shí)現(xiàn)跨域請求,需要的朋友可以參考下
    2024-05-05
  • 詳解C#編程中一維數(shù)組與多維數(shù)組的使用

    詳解C#編程中一維數(shù)組與多維數(shù)組的使用

    這篇文章主要介紹了詳解C#編程中一維數(shù)組與多維數(shù)組的使用,包括數(shù)組初始化等基礎(chǔ)知識的講解,需要的朋友可以參考下
    2016-01-01
  • C# XML字符串包含特殊字符的處理轉(zhuǎn)換方法小結(jié)

    C# XML字符串包含特殊字符的處理轉(zhuǎn)換方法小結(jié)

    今天用C#輸出XML文件時(shí),發(fā)現(xiàn)報(bào)錯(cuò),經(jīng)過反復(fù)檢查調(diào)試,發(fā)現(xiàn)是因?yàn)槟程巸?nèi)容含有某些特殊字符,這些特殊字符是在XML里不被允許的
    2020-07-07
  • C#、vb.net及SQL判斷指定年份是否為閏年的方法

    C#、vb.net及SQL判斷指定年份是否為閏年的方法

    這篇文章主要介紹了C#、vb.net及SQL判斷指定年份是否為閏年的方法,分別以三種方法實(shí)現(xiàn)了判斷閏年的功能,在進(jìn)行項(xiàng)目開發(fā)中具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2014-11-11
  • 詳細(xì)分析c# 運(yùn)算符重載

    詳細(xì)分析c# 運(yùn)算符重載

    這篇文章主要介紹了c# 運(yùn)算符重載的相關(guān)資料,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • WinForm限制窗體不能移到屏幕外的方法

    WinForm限制窗體不能移到屏幕外的方法

    這篇文章主要介紹了WinForm限制窗體不能移到屏幕外的方法,實(shí)例分析了C#中WinForm窗體操作的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-08-08
  • 向一個(gè)數(shù)組中插入一個(gè)1~100的隨機(jī)數(shù)

    向一個(gè)數(shù)組中插入一個(gè)1~100的隨機(jī)數(shù)

    這篇文章主要介紹了如何向一個(gè)數(shù)組中插入一個(gè)1~100的隨機(jī)數(shù),思路很簡單,需要的朋友可以參考下
    2014-07-07
  • C#使用TreeView控件實(shí)現(xiàn)的二叉樹泛型節(jié)點(diǎn)類及其方法

    C#使用TreeView控件實(shí)現(xiàn)的二叉樹泛型節(jié)點(diǎn)類及其方法

    TreeView?控件在?C#?中主要用于顯示分層結(jié)構(gòu)的數(shù)據(jù),這通常是一個(gè)文件系統(tǒng)的表示,但也可以是任何具有父子關(guān)系的數(shù)據(jù)集合,本文給大家介紹了C#使用TreeView控件實(shí)現(xiàn)的二叉樹泛型節(jié)點(diǎn)類及其方法,需要的朋友可以參考下
    2024-03-03

最新評論

固阳县| 永顺县| 壶关县| 视频| 香港| 涟水县| 外汇| 松原市| 深州市| 巴中市| 遂溪县| 嘉兴市| 云阳县| 宜春市| 遂溪县| 商河县| 新民市| 河东区| 伊金霍洛旗| 阆中市| 玛纳斯县| 阳城县| 嘉兴市| 伊吾县| 青阳县| 萨嘎县| 新竹县| 平潭县| 浪卡子县| 西乌珠穆沁旗| 洪江市| 尖扎县| 乌兰浩特市| 水城县| 永德县| 皋兰县| 视频| 贡觉县| 云南省| 汕尾市| 新干县|