2009-03-27 21 views
9

Tôi đang học C#. Từ những gì tôi biết, bạn phải thiết lập mọi thứ một cách chính xác để có bộ thu gom rác thực sự xóa tất cả mọi thứ như nó phải được. Tôi đang tìm kiếm sự khôn ngoan đã học được qua nhiều năm từ bạn, người thông minh.Các cách để giải quyết Rò rỉ bộ nhớ trong C#

Tôi đến từ nền C++ và được sử dụng cho các mẫu mã và mẫu phát triển. Tôi muốn tìm hiểu những gì mùi mã giống như trong C#. Cho tôi lời khuyên!

Cách tốt nhất để xóa mọi thứ là gì?

Làm thế nào bạn có thể tìm ra khi nào bạn bị "rò rỉ bộ nhớ"?


Edit: Tôi cố gắng để phát triển một cú đấm-danh sách các "công cụ để luôn luôn làm cho việc quản lý bộ nhớ"


Cảm ơn, rất nhiều.

Trả lời

17

C#, Khuôn khổ .NET sử dụng bộ nhớ được quản lý và mọi thứ (nhưng phân bổ tài nguyên không được quản lý) là rác được thu thập.

Có thể giả định rằng các loại được quản lý luôn được thu thập rác. Bao gồm arrays, classesstructures. Vui lòng thực hiện int[] stuff = new int[32]; và quên điều đó.

Nếu bạn mở tệp, kết nối cơ sở dữ liệu hoặc bất kỳ tài nguyên không được quản lý nào khác trong lớp, triển khai giao diện IDisposable và trong phương thức Vứt bỏ phân bổ tài nguyên không được quản lý.

Bất kỳ lớp nào triển khai IDisposable phải được đóng một cách rõ ràng hoặc được sử dụng trong (Tôi nghĩ là thú vị) Sử dụng khối như;

using (StreamReader reader = new StreamReader("myfile.txt")) 
{ 
    ... your code here 
} 

Ở đây .NET sẽ loại bỏ trình đọc khi ra khỏi phạm vi {}.

+1

That "hoặc" rất khó hiểu - ngay cả đối tượng IDisposable sẽ trở thành rác. GC không biết gì về IDisposable. Thường Dispose() gọi SuppressFinalize, nhưng đó là không liên quan. –

+0

Điểm tốt. Vì vậy, các lớp có chứa là rác thu thập được, nhưng đó là tài nguyên được explicit deallocated. Tôi chưa bao giờ nghĩ về điều đó. –

+3

"Có thể giả định rằng các loại được quản lý luôn được thu thập rác." Tuyên bố này rất sai. Không có gì có thể được thu thập rác nếu nó vẫn có thể đạt được, lập trình viên phải luôn luôn có trong tâm trí để vô hiệu hóa tài liệu tham khảo gốc của mình khi không còn cần thiết. –

0

Cách tốt nhất để xóa mọi thứ là gì?

LƯU Ý: chỉ hoạt động đối với các loại chứa tài nguyên không được quản lý. Nó không giúp với các loại được quản lý hoàn toàn.

Có lẽ phương pháp tốt nhất là triển khai và thực hiện theo mẫu IDisposable; và gọi phương thức vứt bỏ trên tất cả các đối tượng thực hiện nó.

Tuyên bố 'sử dụng' là người bạn tốt nhất của bạn. Đặt lỏng lẻo, nó sẽ gọi vứt bỏ cho bạn về các đối tượng thực hiện IDisposable.

11

Điều đầu tiên với GC là điều không xác định; nếu bạn muốn tài nguyên được dọn sạch kịp thời, hãy thực hiện IDisposable và sử dụng using; không thu thập bộ nhớ được quản lý, nhưng có thể giúp ích rất nhiều với các tài nguyên không được quản lý và các chuỗi trở đi.

Đặc biệt, điều cần xem ra cho:

  • nhiều ghim (đặt rất nhiều hạn chế về những gì có thể làm GC)
  • nhiều finalizers (bạn thường không cần đến chúng; chậm GC)
  • sự kiện tĩnh - cách đơn giản để giữ cho rất nhiều đối tượng lớn đồ thị sống ;-p
  • sự kiện trên một đối tượng tuổi thọ cao không tốn kém, có thể thấy một vật đắt tiền mà lẽ ra phải được dọn dẹp
  • " các biến bị bắt "vô tình giữ biểu đồ còn sống

Để điều tra rò rỉ bộ nhớ ..." SOS "là một trong những tuyến đường dễ nhất; bạn có thể sử dụng SOS để tìm tất cả các trường hợp của một loại và những gì có thể nhìn thấy, v.v.

+1

amen cho các sự kiện tĩnh nguy hiểm. – Quibblesome

3

Nói chung, bạn càng lo lắng về phân bổ bộ nhớ trong C# thì bạn càng tốt. Tôi sẽ để nó cho một hồ sơ để cho tôi biết khi tôi gặp vấn đề với bộ sưu tập.

Bạn không thể tạo rò rỉ bộ nhớ trong C# giống như cách bạn làm trong C++. Các nhà sưu tập rác sẽ luôn luôn "có lưng của bạn". Những gì bạn có thể làm là tạo các đối tượng và giữ tham chiếu đến chúng ngay cả khi bạn không bao giờ sử dụng chúng. Đó là một mùi mã để tìm ra.

Ngoài ra:

  • Có một số khái niệm thường xuyên như thế nào bộ sưu tập sẽ xảy ra (vì lý do hiệu suất)
  • Đừng giữ tham chiếu đến đối tượng còn hơn bạn cần
  • Vứt bỏ các đối tượng thực hiện IDisposable ngay sau khi bạn đã hoàn tất với chúng (sử dụng cú pháp using)
  • Thực hiện đúng cách IDisposable interface
0

Bạn có thể sử dụng các công cụ như CLR profiler phải mất một chút thời gian để tìm hiểu cách sử dụng nó một cách chính xác, nhưng sau khi tất cả đều miễn phí. (Nó đã giúp tôi nhiều lần để tìm rò rỉ bộ nhớ của tôi)

2

Các nguồn chính của rò rỉ bộ nhớ tôi có thể nghĩ đến là:

  • giữ tham chiếu đến đối tượng mà bạn không cần nữa (thường là trong một số Vì vậy, ở đây bạn cần phải nhớ rằng tất cả những thứ mà bạn thêm vào một bộ sưu tập mà bạn có tham chiếu cũng sẽ nằm trong bộ nhớ.

  • Có tham chiếu vòng tròn, ví dụ: có đại biểu được đăng ký với một sự kiện. Vì vậy, mặc dù bạn rõ ràng không tham chiếu đến một đối tượng, nó không thể lấy rác được thu thập bởi vì một trong các phương thức của nó được đăng ký như một đại biểu với một sự kiện. Trong những trường hợp này, bạn cần nhớ xóa đại biểu trước khi hủy tham chiếu.

  • Tương tác với mã gốc và không giải phóng được. Ngay cả khi bạn sử dụng trình bao bọc được quản lý để triển khai trình kết xuất, thường thì CLR không làm sạch chúng đủ nhanh, bởi vì nó không hiểu được dấu chân bộ nhớ.Bạn nên sử dụng mẫu sử dụng (IDisposable) {}
+1

"tham chiếu vòng tròn" không phải là vấn đề thực sự - vấn đề là một trong hai mục vẫn * có thể * được nhìn thấy một cách hợp lệ, và sự kiện này đang giữ đối tượng thứ hai còn sống. –

1

Một điều khác cần xem xét để quản lý bộ nhớ là nếu bạn đang triển khai bất kỳ mẫu Observer nào và không loại bỏ các tham chiếu một cách chính xác.

Ví dụ: Đối tượng Đồng hồ Object B Đối tượng B được xử lý nếu tham chiếu từ A đến B không được xử lý tài sản mà GC sẽ không xử lý đúng cách đối tượng. Do việc xử lý sự kiện vẫn được gán, GC không xem nó như là một tài nguyên không được sử dụng.

Nếu bạn có một nhóm nhỏ các đối tượng bạn đang làm việc với điều này có thể khiến tôi không liên quan. Tuy nhiên, nếu bạn làm việc với hàng ngàn đối tượng, điều này có thể làm tăng dần bộ nhớ trong suốt thời gian của ứng dụng.

Có một số ứng dụng phần mềm quản lý bộ nhớ tuyệt vời để theo dõi những gì đang xảy ra với đống ứng dụng của bạn. Tôi tìm thấy lợi ích lớn từ việc sử dụng .Net Memory Profiler.

HTH

1

tôi khuyên bạn nên sử dụng .NET Memory Profiler

NET Memory Profiler là một công cụ mạnh mẽ cho việc tìm kiếm rò rỉ bộ nhớ và tối ưu hóa việc sử dụng bộ nhớ trong các chương trình viết bằng C#, VB.NET hoặc bất kỳ .NET khác Ngôn ngữ.

NET Memory Profiler sẽ giúp bạn:

  • Xem real-time bộ nhớ và tài nguyên thông tin
  • Dễ dàng xác định rò rỉ bộ nhớ bằng cách thu thập và so sánh những bức ảnh của bộ nhớ NET
  • Tìm trường mà không được xử lý đúng cách
  • Nhận thông tin chi tiết về việc sử dụng tài nguyên không được quản lý
  • Tối ưu hóa việc sử dụng bộ nhớ
  • tra vấn đề bộ nhớ trong mã sản xuất
  • Thực hiện bộ nhớ tự động kiểm tra
  • Lấy thông tin về bộ nhớ quê hương

Hãy xem video hướng dẫn của họ:

http://memprofiler.com/tutorials/

0

Cách tốt nhất để đảm bảo các đối tượng bị xóa, hoặc trong .NET lingo, garbage-collected, là để đảm bảo rằng tất cả các tham chiếu gốc (các tham chiếu có thể được truy tìm thông qua các phương thức và đối tượng đến phương thức đầu tiên trên một ngăn xếp cuộc gọi của chủ đề) cho một đối tượng được đặt thành rỗng.

GC không thể, và sẽ không, thu thập một đối tượng nếu có bất kỳ tham chiếu bắt nguồn từ nó, không có vấn đề cho dù nó thực hiện IDisposable hay không.

Tham chiếu thông tư không áp dụng hình phạt hoặc khả năng rò rỉ bộ nhớ, vì GC đánh dấu các đối tượng mà nó đã truy cập trong biểu đồ đối tượng. Trong trường hợp các đại biểu hoặc người tổ chức sự kiện, có thể quên bỏ tham chiếu trong một sự kiện thành một phương thức đích, vì vậy mà đối tượng có chứa phương thức đích không thể được thu thập nếu sự kiện được bắt nguồn.

1

Những người khác đã đề cập đến tầm quan trọng của IDisposable và một số điều cần lưu ý trong mã của bạn.

Tôi muốn đề xuất một số tài nguyên bổ sung; Tôi tìm thấy điều sau đây vô giá khi học các chi tiết của .NET GC và cách khắc phục sự cố bộ nhớ trong các ứng dụng .NET.

CLR via C# bởi Jeffrey Richter là xuất sắc cuốn sách. Đáng giá mua chỉ cho chương về GC và bộ nhớ.

blog (bởi "Kỹ sư leo thang ASP.NET" của Microsoft) thường là nguồn của tôi để tìm các mẹo và thủ thuật để sử dụng WinDbg, SOS và để phát hiện một số loại rò rỉ bộ nhớ nhất định. Tess thậm chí được thiết kế .NET debugging demo/labs sẽ hướng dẫn bạn thông qua các vấn đề bộ nhớ phổ biến và cách nhận ra và giải quyết chúng.

Debugging Tools for Windows (WinDbg, SOS, vv)

+0

Tess 'blog là hoàn toàn được đề nghị cho chủ đề này, có. –

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