2010-03-24 28 views
10

Tôi đang cố gắng hiểu chuỗi thực tập và tại sao dường như không hoạt động trong ví dụ của tôi. Điểm của ví dụ là để hiển thị Ví dụ 1 sử dụng ít hơn (bộ nhớ ít hơn rất nhiều) vì nó chỉ nên có 10 chuỗi trong bộ nhớ. Tuy nhiên, trong đoạn code dưới đây cả hai ví dụ sử dụng khoảng cùng một lượng bộ nhớ (kích thước ảo và bộ làm việc).C# string interning

Hãy tư vấn tại sao ví dụ 1 không sử dụng ít bộ nhớ hơn nhiều? Cảm ơn

Ví dụ 1:

 IList<string> list = new List<string>(10000); 

     for (int i = 0; i < 10000; i++) 
     { 
      for (int k = 0; k < 10; k++) 
      { 
       list.Add(string.Intern(k.ToString())); 
      } 

     } 

     Console.WriteLine("intern Done"); 
     Console.ReadLine(); 

Ví dụ 2:

 IList<string> list = new List<string>(10000); 

     for (int i = 0; i < 10000; i++) 
     { 
      for (int k = 0; k < 10; k++) 
      { 
       list.Add(k.ToString()); 
      } 

     } 

     Console.WriteLine("intern Done"); 
     Console.ReadLine(); 
+1

Không phải là câu hỏi này rất giống một bạn hỏi ngày hôm qua? http://stackoverflow.com/questions/2502522/string-interning-should-this-code-only-create-10-strings-in-memory –

+0

có giống nhau, nhưng không giống nhau – CodingThunder

Trả lời

2

Từ Thứ hai msdn, để thực tập một chuỗi, trước tiên bạn phải tạo ra các chuỗi. Bộ nhớ được sử dụng bởi đối tượng String vẫn phải được cấp phát, mặc dù bộ nhớ cuối cùng sẽ được thu thập rác.

16

Vấn đề là ToString() vẫn sẽ phân bổ một chuỗi mới, và sau đó thực tập nó. Nếu bộ thu gom rác không chạy để thu thập các chuỗi "tạm thời" đó, thì việc sử dụng bộ nhớ sẽ giống nhau.

Ngoài ra, độ dài của các chuỗi của bạn khá ngắn. 10.000 chuỗi mà chủ yếu chỉ có một ký tự dài là một sự khác biệt bộ nhớ khoảng 20KB mà bạn có thể sẽ không nhận thấy. Hãy thử sử dụng các chuỗi dài hơn (hoặc nhiều hơn trong số chúng) và thực hiện thu thập rác trước khi bạn kiểm tra mức sử dụng bộ nhớ.

Dưới đây là một ví dụ mà không thấy một sự khác biệt:

class Program 
{ 
    static void Main(string[] args) 
    { 
     int n = 100000; 

     if (args[0] == "1") 
      WithIntern(n); 
     else 
      WithoutIntern(n); 
    } 

    static void WithIntern(int n) 
    { 
     var list = new List<string>(n); 

     for (int i = 0; i < n; i++) 
     { 
      for (int k = 0; k < 10; k++) 
      { 
       list.Add(string.Intern(new string('x', k * 1000))); 
      } 
     } 

     GC.Collect(); 
     Console.WriteLine("Done."); 
     Console.ReadLine(); 
    } 

    static void WithoutIntern(int n) 
    { 
     var list = new List<string>(n); 

     for (int i = 0; i < n; i++) 
     { 
      for (int k = 0; k < 10; k++) 
      { 
       list.Add(new string('x', k * 1000)); 
      } 
     } 

     GC.Collect(); 
     Console.WriteLine("Done."); 
     Console.ReadLine(); 
    } 
} 
+2

Điển hình vi tối ưu hóa mà chỉ đơn giản là không cho thấy những gì nó được cho là phải làm. – TomTom

+0

Kết quả tương tự với GC.Collect và sử dụng các chuỗi lớn hơn .... hrmmmm – CodingThunder

+0

@ TomTom: Cái gì? – CodingThunder

7

Hãy nhớ rằng, CLR quản lý bộ nhớ thay mặt cho quá trình của bạn, vì vậy thật khó để tìm ra dấu chân bộ nhớ được quản lý từ việc xem kích thước ảo và bộ làm việc. CLR thường sẽ cấp phát và giải phóng bộ nhớ trong các khối. Kích thước của các thay đổi tùy theo chi tiết thực hiện, nhưng do điều này là không thể đo lường việc sử dụng đống được quản lý dựa trên bộ đếm bộ nhớ cho quá trình.

Tuy nhiên, nếu bạn nhìn vào mức sử dụng bộ nhớ thực tế cho các ví dụ, bạn sẽ thấy sự khác biệt.

Ví dụ 1

0:005>!dumpheap -stat 
... 
00b6911c  137   4500 System.String 
0016be60  8  480188  Free 
00b684c4  14  649184 System.Object[] 
Total 316 objects 
0:005> !eeheap -gc 
Number of GC Heaps: 1 
generation 0 starts at 0x01592dcc 
generation 1 starts at 0x01592dc0 
generation 2 starts at 0x01591000 
ephemeral segment allocation context: none 
segment begin allocated  size 
01590000 01591000 01594dd8 0x00003dd8(15832) 
Large object heap starts at 0x02591000 
segment begin allocated  size 
02590000 02591000 026a49a0 0x001139a0(1128864) 
Total Size 0x117778(1144696) 
------------------------------ 
GC Heap Size 0x117778(1144696) 

Ví dụ 2

0:006> !dumpheap -stat 
... 
00b684c4  14  649184 System.Object[] 
00b6911c 100137  2004500 System.String 
Total 100350 objects 
0:006> !eeheap -gc 
Number of GC Heaps: 1 
generation 0 starts at 0x0179967c 
generation 1 starts at 0x01791038 
generation 2 starts at 0x01591000 
ephemeral segment allocation context: none 
segment begin allocated  size 
01590000 01591000 0179b688 0x0020a688(2139784) 
Large object heap starts at 0x02591000 
segment begin allocated  size 
02590000 02591000 026a49a0 0x001139a0(1128864) 
Total Size 0x31e028(3268648) 
------------------------------ 
GC Heap Size 0x31e028(3268648) 

Như bạn có thể thấy từ kết quả trên ví dụ thứ hai không sử dụng thêm bộ nhớ trên heap quản lý.

0

Nguồn:https://blogs.msdn.microsoft.com/ericlippert/2009/09/28/string-interning-and-string-empty/

Chuỗi interning là một kỹ thuật tối ưu hóa bởi trình biên dịch. Nếu bạn có hai chuỗi ký tự giống hệt nhau trong một đơn vị biên dịch thì mã được tạo ra đảm bảo rằng chỉ có một đối tượng chuỗi được tạo cho tất cả cá thể của chữ đó (các ký tự kèm theo dấu ngoặc kép) trong assembly.

Ví dụ:

object obj = "Int32"; 
string str1 = "Int32"; 
string str2 = typeof(int).Name; 

đầu ra của so sánh sau:

Console.WriteLine(obj == str1); // true 
Console.WriteLine(str1 == str2); // true  
Console.WriteLine(obj == str2); // false !? 

Note1: Đối tượng được so sánh bằng cách tham khảo.

Note2: typeof (int) .Name được đánh giá theo phương pháp phản chiếu để nó không được đánh giá vào thời gian biên dịch. Dưới đây là những so sánh này được thực hiện tại thời gian biên dịch.

Phân tích các kết quả:

  1. đúng bởi vì cả hai đều chứa cùng một nghĩa đen và do đó mã được tạo ra sẽ chỉ có một đối tượng tham khảo "Int32". Xem Lưu ý 1.

  2. đúng vì nội dung của cả hai giá trị được chọn giống nhau.

  3. sai vì str2 và obj không có cùng một chữ. Xem Note 2.

+1

Vui lòng không đăng câu trả lời giống nhau cho nhiều câu hỏi. Nếu các câu hỏi về cơ bản giống nhau, [gắn cờ chúng] (https://stackoverflow.com/privileges/flag-posts) làm bản sao. Nếu không, hãy tùy chỉnh câu trả lời cho câu hỏi. –