2013-05-14 30 views
7

Tôi đã tải xuống luồng dưới dạng byte [] 'thô' khoảng 36MB. sau đó tôi chuyển đổi đó vào một chuỗi vớistring.replace vs StringBuilder.replace cho bộ nhớ

string temp = System.Text.Encoding.UTF8.GetString(raw) 

Sau đó, tôi cần phải thay thế tất cả "\ n" với "\ r \ n" vì vậy tôi cố gắng

string temp2 = temp.Replace("\n","\r\n") 

nhưng nó ném một "Out of Memory " ngoại lệ. Sau đó, tôi đã cố tạo một chuỗi mới bằng StringBuilder:

string temp2 = new StringBuilder(temp).Replace("\n","\r\n").toString() 

và nó không loại trừ ngoại lệ. Tại sao sẽ có một vấn đề bộ nhớ ở nơi đầu tiên (tôi chỉ giao dịch với 36MB ở đây), nhưng cũng tại sao StringBuilder.Replace() làm việc khi khác không?

+0

Tôi đã thấy câu hỏi đó, nhưng nó có nhiều việc phải làm với hiệu suất hơn là sử dụng bộ nhớ. Ngoài ra, đây còn là một "chuyện gì đang xảy ra đằng sau hiện trường?" câu hỏi hơn là "làm thế nào để sửa chữa nó?" một. – Aeon2058

Trả lời

5

Khi bạn sử dụng:

string temp2 = temp.Replace("\n","\r\n") 

cho mỗi trận đấu của "\ n" trong temp chuỗi, hệ thống sẽ tạo một chuỗi mới với sự thay thế.

Với StringBuilder, điều này không xảy ra vì StringBuilder có thể thay đổi, do đó bạn có thể sửa đổi cùng một đối tượng mà không cần phải tạo một đối tượng khác.

Ví dụ:

temp = "test1\ntest2\ntest3\n" 

Với Phương pháp đầu tiên (string)

string temp2 = temp.Replace("\n","\r\n") 

tương đương với

string aux1 = "test1\r\ntest2\ntest3\n" 
string aux2 = "test1\r\ntest2\r\ntest3\n" 
string temp2 = "test1\r\ntest2\r\ntest3\r\n" 

Với Secon Method (Strin gBuilder)

string temp2 = new StringBuilder(temp).Replace("\n","\r\n").toString() 

tương đương với

Stringbuilder aux = "test1\ntest2\ntest3\n" 
aux = "test1\r\ntest2\ntest3\n" 
aux = "test1\r\ntest2\r\ntest3\n" 
aux = "test1\r\ntest2\r\ntest3\r\n" 
string temp2 = aux.toString() 
+1

Vì vậy, nếu chuỗi của tôi dài 36MB và đã nói 50.000 "\ n" để thay thế, với string.Replace() điều này sẽ yêu cầu 36 * 50000MB để thực hiện, và đó là lý do tại sao có một lỗi bộ nhớ? Không nên gc được thực hiện trên aux1, aux2, aux3 ... vv vì chúng không còn cần thiết nữa? – Aeon2058

+0

Điều này có vẻ không chính xác. Mã nguồn C++ gốc string.Replace chạy có sẵn tại https://github.com/fixdpt/shared-source-cli-2.0/blob/master/clr/src/vm/comstring.cpp#L1572. Đầu tiên nó lặp lại chuỗi, tìm tất cả các chỉ số của các lớp nền sẽ được thay thế. Sau đó, nó phân bổ chính xác số lượng bộ nhớ phù hợp dựa trên đó. Sau đó, nó lặp lại chuỗi một lần nữa, sao chép bản gốc vào bộ đệm mới, thực hiện thay thế khi cần thiết. –

3

Sau StringBuilder từ MSDN:

Hầu hết các phương pháp sửa đổi một thể hiện của lớp này trả về một tài liệu tham khảo để cùng dụ và bạn có thể gọi một phương thức hoặc thuộc tính để tham khảo. Điều này có thể thuận tiện nếu bạn muốn viết một câu lệnh duy nhất liên kết các hoạt động liên tiếp.

Vì vậy, khi bạn gọi thay thế bằng String, đối tượng mới (dữ liệu lớn - 36MB) sẽ được cấp phát để tạo chuỗi mới. Nhưng StringBuilder truy cập các đối tượng cùng một đối tượng và không tạo một đối tượng mới.

0

Chuỗi không thay đổi được trong C#. Nếu bạn sử dụng phương thức string.replace(), hệ thống sẽ tạo một đối tượng String cho mỗi thay thế. Lớp StringBuilder sẽ giúp bạn tránh tạo đối tượng.

1

Có khái niệm về áp lực bộ nhớ, có nghĩa là các đối tượng tạm thời được tạo, bộ sưu tập rác thường xuyên hơn chạy.

Vì vậy: StringBuilder tạo ít đối tượng tạm thời hơn và tăng thêm áp lực bộ nhớ.

StringBuilder Memory

Thay

Tiếp theo chúng ta sử dụng StringBuilder để thay thế ký tự trong vòng lặp. Đầu tiên chuyển đổi chuỗi thành một StringBuilder, và sau đó gọi các phương thức StringBuilder. Điều này nhanh hơn — loại StringBuilder sử dụng các mảng ký tự nội bộ

Các vấn đề liên quan