Khi nào được chấp nhận để gọi GC.Collect?


166

Lời khuyên chung là bạn không nên gọi GC.Collecttừ mã của mình, nhưng các ngoại lệ cho quy tắc này là gì?

Tôi chỉ có thể nghĩ về một vài trường hợp rất cụ thể trong đó có thể có ý nghĩa để buộc một bộ sưu tập rác.

Một ví dụ cho thấy tâm trí là một dịch vụ, thức dậy trong khoảng thời gian, thực hiện một số nhiệm vụ và sau đó ngủ trong một thời gian dài. Trong trường hợp này, có thể là một ý tưởng tốt để buộc một bộ sưu tập để ngăn quá trình sắp tới không hoạt động để giữ nhiều bộ nhớ hơn mức cần thiết.

Có trường hợp nào khác mà nó được chấp nhận để gọi GC.Collect?


Câu trả lời:


153

Nếu bạn có lý do chính đáng để tin rằng một nhóm đối tượng quan trọng - đặc biệt là những đối tượng mà bạn nghi ngờ là ở thế hệ 1 và 2 - hiện đủ điều kiện để thu gom rác, và bây giờ sẽ là thời điểm thích hợp để thu thập về hiệu suất nhỏ .

Một ví dụ điển hình của việc này là nếu bạn vừa đóng một biểu mẫu lớn. Bạn biết rằng tất cả các điều khiển UI bây giờ có thể là rác được thu thập và tạm dừng rất ngắn vì biểu mẫu được đóng có thể sẽ không được người dùng chú ý.

CẬP NHẬT 2.7.2018

Kể từ .NET 4.5 - có GCLatencyMode.LowLatencyGCLatencyMode.SustainedLowLatency. Khi vào và rời một trong hai chế độ này, bạn nên sử dụng toàn bộ GC GC.Collect(2, GCCollectionMode.Forced).

Kể từ .NET 4.6 - có GC.TryStartNoGCRegionphương thức (được sử dụng để đặt giá trị chỉ đọc GCLatencyMode.NoGCRegion). Điều này có thể tự nó, thực hiện một bộ sưu tập rác chặn đầy đủ trong một nỗ lực để giải phóng đủ bộ nhớ, nhưng do chúng tôi không đồng ý với GC trong một khoảng thời gian, tôi cho rằng đó cũng là một ý tưởng tốt để thực hiện đầy đủ GC trước và sau.

Nguồn: Kỹ sư Microsoft Ben Watson's: Viết mã .NET hiệu suất cao , 2nd Ed. 2018.

Xem:


8
Theo mã nguồn MS gọi GC.Collect (2) cứ sau 850ms là ổn. Đừng tin? Sau đó, chỉ cần xem PresentationCore.dll, MS.Iternal.MemoryPressure.ProcessAdd (). Tôi hiện có một ứng dụng xử lý hình ảnh (hình ảnh nhỏ, không có áp lực bộ nhớ thực) trong đó việc gọi GC.Collect (2) mất hơn 850ms và do đó toàn bộ ứng dụng bị đóng băng bởi điều này (ứng dụng dành 99,7% thời gian trong GC).
springy76

36
@ springy76: Được Microsoft thực hiện ở một nơi không có nghĩa là nó được coi là một điều tốt bởi những người đưa ra lời khuyên từ Microsoft ...
Jon Skeet

4
Tôi không thích ví dụ đó. Những gì đang làm thơ sau khi đóng nó? Một ví dụ điển hình tôi thấy là sau khi tải cấp trò chơi trên XBox hoặc WindowsPhone. Trên các nền tảng đó, GC chạy sau khi phân bổ 1MB hoặc sth như thế. Vì vậy, thật tốt khi phân bổ càng nhiều càng tốt trong khi tải cấp độ (trong khi hiển thị một số màn hình giật gân) và sau đó thực hiện GC.Collect để cố gắng tránh các bộ sưu tập trong trò chơi.
Piotr Perak

8
@Peri: Điểm quan trọng của việc thực hiện sau khi đóng là bạn vừa tạo ra một loạt các đối tượng (điều khiển, dữ liệu bạn đang hiển thị) đủ điều kiện để thu gom rác - vì vậy, bằng cách gọi GC.Collectvề cơ bản bạn sẽ nói với người thu gom rác mà bạn biết tốt hơn nó cho một sự thay đổi. Tại sao bạn không thích ví dụ này?
Jon Skeet

6
@SHCJ: GC.Collect()sẽ yêu cầu GC thực hiện một bộ sưu tập đầy đủ . Nếu bạn biết rằng bạn vừa tạo ra rất nhiều đối tượng tồn tại trước đây đủ điều kiện để thu gom rác bạn tin rằng người dùng sẽ ít nhận thấy sự tạm dừng nhẹ hơn sau này, có vẻ như hoàn toàn hợp lý khi nghĩ rằng bây giờ tốt hơn thời gian để nhắc một bộ sưu tập hơn là để nó xảy ra sau này.
Jon Skeet

50

Tôi GC.Collectchỉ sử dụng khi viết các giàn kiểm tra hiệu suất thô / profiler; tức là tôi có hai (hoặc nhiều) khối mã để kiểm tra - đại loại như:

GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
TestA(); // may allocate lots of transient objects
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
TestB(); // may allocate lots of transient objects
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
...

Vì vậy, TestA()TestB()chạy với trạng thái tương tự nhất có thể - tức là TestB()không bị tấn công chỉ vì TestAđể nó rất gần với điểm tới hạn.

Một ví dụ cổ điển sẽ là một exe giao diện điều khiển đơn giản ( Mainví dụ, một loại phương pháp đủ để được đăng ở đây), cho thấy sự khác biệt giữa nối chuỗi chuỗi và StringBuilder.

Nếu tôi cần một cái gì đó chính xác, thì đây sẽ là hai thử nghiệm hoàn toàn độc lập - nhưng thường thì điều này là đủ nếu chúng tôi chỉ muốn giảm thiểu (hoặc bình thường hóa) GC trong các thử nghiệm để có cảm giác thô bạo đối với hành vi.

Trong quá trình sản xuất mã? Tôi vẫn chưa sử dụng nó ;-p


1
Và tôi có thể thêm "WaitForPendingFinalulators" (hoặc bất cứ điều gì) trong trường hợp này ;-p
Marc Gravell

29

Thực hành tốt nhất là không ép buộc thu gom rác trong hầu hết các trường hợp. (Mọi hệ thống tôi đã làm việc trên đó có các bộ sưu tập rác bắt buộc, đã nhấn mạnh các vấn đề mà nếu được giải quyết sẽ loại bỏ sự cần thiết phải thu gom rác và tăng tốc hệ thống lên rất nhiều.)

Có một vài trường hợp khi bạn biết thêm về việc sử dụng bộ nhớ thì trình thu gom rác thực hiện. Điều này khó có thể đúng trong một ứng dụng đa người dùng hoặc một dịch vụ đáp ứng nhiều hơn một yêu cầu tại một thời điểm.

Tuy nhiên, trong một số loại xử lý hàng loạt, bạn biết nhiều hơn về GC. Ví dụ xem xét một ứng dụng mà.

  • Được cung cấp một danh sách các tên tệp trên dòng lệnh
  • Xử lý một tệp duy nhất sau đó ghi kết quả ra tệp kết quả.
  • Trong khi xử lý tệp, tạo rất nhiều đối tượng được liên kết với nhau không thể được thu thập cho đến khi quá trình xử lý tệp hoàn tất (ví dụ: cây phân tích cú pháp)
  • Không giữ trạng thái khớp giữa các tệp mà nó đã xử lý .

Bạn thể thực hiện một trường hợp (sau khi cẩn thận) kiểm tra rằng bạn nên buộc một bộ sưu tập rác đầy đủ sau khi bạn xử lý từng tệp.

Một trường hợp khác là dịch vụ thức dậy cứ sau vài phút để xử lý một số mặt hàng và không giữ bất kỳ trạng thái nào trong khi nó đang ngủ . Sau đó, buộc một bộ sưu tập đầy đủ ngay trước khi đi ngủ thể đáng giá.

Lần duy nhất tôi sẽ xem xét việc buộc một bộ sưu tập là khi tôi biết rằng rất nhiều đối tượng đã được tạo gần đây và rất ít đối tượng hiện đang được tham chiếu.

Tôi thà có một API bộ sưu tập rác khi tôi có thể đưa ra gợi ý về loại điều này mà không cần phải tự buộc mình.

Xem thêm " Tidbits hiệu suất của Rico Mariani "



11

Trong các hệ thống lớn 24/7 hoặc 24/6 - các hệ thống phản ứng với tin nhắn, RPC yêu cầu hoặc thăm dò cơ sở dữ liệu hoặc xử lý liên tục - rất hữu ích khi có cách xác định rò rỉ bộ nhớ. Đối với điều này, tôi có xu hướng thêm một cơ chế vào ứng dụng để tạm thời đình chỉ mọi xử lý và sau đó thực hiện thu gom rác đầy đủ. Điều này đặt hệ thống vào trạng thái không hoạt động trong đó bộ nhớ còn lại là bộ nhớ tồn tại lâu dài (bộ nhớ cache, cấu hình, & c.) Hoặc nếu không thì bị "rò rỉ" (các đối tượng không mong muốn hoặc không muốn được root nhưng thực tế là vậy).

Có cơ chế này giúp cho việc sử dụng bộ nhớ dễ dàng hơn rất nhiều vì các báo cáo sẽ không bị che mờ bởi tiếng ồn từ quá trình xử lý đang hoạt động.

Để chắc chắn bạn nhận được tất cả rác, bạn cần thực hiện hai bộ sưu tập:

GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();

Vì bộ sưu tập đầu tiên sẽ khiến bất kỳ đối tượng nào có bộ hoàn thiện được hoàn thành (nhưng thực tế không phải rác thu thập các đối tượng này). GC thứ hai sẽ thu gom rác các đối tượng hoàn thiện này.


Bây giờ tôi đã thấy bộ sưu tập hai lượt ở một vài nơi, nhưng sau khi đọc đoạn văn trong tài liệu MSDN cho GC.WaitForPendingFinalulators nói: "Đợi tất cả các công cụ hoàn tất trước khi tiếp tục. Nếu không có cuộc gọi này đến GC.WaitForPendingFinalulators, vòng lặp worker bên dưới có thể thực thi cùng lúc với các bộ hoàn thiện. Với lệnh gọi này, vòng lặp worker chỉ thực hiện sau khi tất cả các bộ hoàn thiện đã được gọi. " Tôi chỉ là một kẻ hoang tưởng. Bạn có biết một nguồn dứt khoát để thực hiện hai đường chuyền?
jerhewet

1
@jerhewet: Chìa khóa để hiểu lý do tại sao hai bộ sưu tập được yêu cầu là tìm hiểu những gì xảy ra với các đối tượng với bộ hoàn thiện. Thật không may, tôi không có chính xác những gì bạn đang yêu cầu, nhưng đã đọc bài viết nàycâu hỏi này trên SO .
Paul Ruane

10

Bạn có thể gọi GC.Collect () khi bạn biết điều gì đó về bản chất của ứng dụng mà trình thu gom rác không có. Thật hấp dẫn khi nghĩ rằng, với tư cách là tác giả, điều này rất có thể. Tuy nhiên, sự thật là số tiền của GC là một hệ thống chuyên gia được viết và kiểm tra khá tốt, và hiếm khi bạn biết điều gì về các đường dẫn mã cấp thấp mà nó không có.

Ví dụ tốt nhất tôi có thể nghĩ về nơi bạn có thể có một số thông tin bổ sung là một ứng dụng xoay vòng giữa thời gian nhàn rỗi và thời gian rất bận rộn. Bạn muốn hiệu suất tốt nhất có thể cho các giai đoạn bận rộn và do đó muốn sử dụng thời gian nhàn rỗi để làm sạch.

Tuy nhiên, hầu hết thời gian, GC đủ thông minh để làm điều này.


8

Là một giải pháp phân mảnh bộ nhớ. Tôi đã thoát khỏi ngoại lệ bộ nhớ trong khi viết rất nhiều dữ liệu vào luồng bộ nhớ (đọc từ luồng mạng). Dữ liệu được viết thành 8K. Sau khi đạt 128M, đã có ngoại lệ mặc dù có rất nhiều bộ nhớ khả dụng (nhưng nó bị phân mảnh). Gọi GC.Collect () đã giải quyết vấn đề. Tôi đã có thể xử lý hơn 1G sau khi sửa chữa.


7

Hãy xem bài viết này của Rico Mariani. Anh ta đưa ra hai quy tắc khi gọi GC.Collect (quy tắc 1 là: "Đừng"):

Khi nào cần gọi GC.Collect ()


3
Đã ở đó rồi. Tôi không cố gắng tìm lý do để làm điều gì đó mà bạn không nên làm, nhưng tôi muốn biết liệu có trường hợp cụ thể nào được chấp nhận hay không.
Brian Rasmussen

5

Một trường hợp gần như cần thiết để gọi GC.Collect () là khi tự động hóa Microsoft Office thông qua Interop. Các đối tượng COM cho Office không muốn tự động phát hành và có thể dẫn đến các trường hợp sản phẩm Office chiếm dung lượng bộ nhớ rất lớn. Tôi không chắc đây là một vấn đề hay do thiết kế. Có rất nhiều bài viết về chủ đề này trên internet vì vậy tôi sẽ không đi sâu vào chi tiết.

Khi lập trình bằng Interop, mọi đối tượng COM đơn lẻ sẽ được phát hành thủ công, thường là mặc dù sử dụng Marshal.ReleseComObject (). Ngoài ra, gọi Bộ sưu tập Rác thủ công có thể giúp "dọn dẹp" một chút. Gọi mã sau đây khi bạn hoàn thành với các đối tượng Interop có vẻ giúp ích khá nhiều:

GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()

Theo kinh nghiệm cá nhân của tôi, sử dụng kết hợp ReleaseComObject và gọi bộ sưu tập rác thủ công giúp giảm đáng kể việc sử dụng bộ nhớ của các sản phẩm Office, cụ thể là Excel.


vâng tôi đã chạy vào đó với .net truy cập excel cũng hoạt động thông qua các đối tượng com. Điều quan trọng cần lưu ý là, điều này sẽ không hoạt động tốt trong chế độ DEBUG vì các hoạt động của GC bị hạn chế ở đó. Nó sẽ hoạt động như dự định chỉ trong chế độ ĐÁNG TIN CẬY. liên kết có liên quan: stackoverflow.com/questions/17130382/ từ
Blechdose

5

Tôi đã làm một số thử nghiệm hiệu suất trên mảng và danh sách:

private static int count = 100000000;
private static List<int> GetSomeNumbers_List_int()
{
    var lstNumbers = new List<int>();
    for(var i = 1; i <= count; i++)
    {
        lstNumbers.Add(i);
    }
    return lstNumbers;
}
private static int[] GetSomeNumbers_Array()
{
    var lstNumbers = new int[count];
    for (var i = 1; i <= count; i++)
    {
        lstNumbers[i-1] = i + 1;
    }
    return lstNumbers;
}
private static int[] GetSomeNumbers_Enumerable_Range()
{
    return  Enumerable.Range(1, count).ToArray();
}

static void performance_100_Million()
{
    var sw = new Stopwatch();

    sw.Start();
    var numbers1 = GetSomeNumbers_List_int();
    sw.Stop();
    //numbers1 = null;
    //GC.Collect();
    Console.WriteLine(String.Format("\"List<int>\" took {0} milliseconds", sw.ElapsedMilliseconds));

    sw.Reset();
    sw.Start();
    var numbers2 = GetSomeNumbers_Array();
    sw.Stop();
    //numbers2 = null;
    //GC.Collect();
    Console.WriteLine(String.Format("\"int[]\" took {0} milliseconds", sw.ElapsedMilliseconds));

    sw.Reset();
    sw.Start();
//getting System.OutOfMemoryException in GetSomeNumbers_Enumerable_Range method
    var numbers3 = GetSomeNumbers_Enumerable_Range();
    sw.Stop();
    //numbers3 = null;
    //GC.Collect();

    Console.WriteLine(String.Format("\"int[]\" Enumerable.Range took {0} milliseconds", sw.ElapsedMilliseconds));
}

và tôi đã nhận được OutOfMemoryExceptiontrong phương thức GetSomeNumbers_Enumerable_Range, cách giải quyết duy nhất là giải phóng bộ nhớ bằng cách:

numbers = null;
GC.Collect();

Tại sao lại bỏ phiếu? câu trả lời của tôi là một ví dụ chứng minh khi nào nên gọi GC. Bạn có một đề nghị tốt hơn? Bạn được chào đón để trình bày.
Daniel B

4

Trong ví dụ của bạn, tôi nghĩ rằng việc gọi GC.Collect không phải là vấn đề, mà là có vấn đề về thiết kế.

Nếu bạn định thức dậy trong khoảng thời gian, (đặt thời gian) thì chương trình của bạn sẽ được tạo cho một lần thực hiện (thực hiện nhiệm vụ một lần) và sau đó chấm dứt. Sau đó, bạn thiết lập chương trình như một tác vụ theo lịch trình để chạy theo các khoảng thời gian đã lên lịch.

Bằng cách này, bạn không phải lo lắng về việc gọi cho GC.Collect, (điều mà bạn hiếm khi nên làm , phải làm).

Điều đó đang được nói, Rico Mariani có một bài đăng blog tuyệt vời về chủ đề này, có thể được tìm thấy ở đây:

http://bloss.msdn.com/ricom/archive/2004/11/29/271829.aspx


3

Một nơi hữu ích để gọi GC.Collect () là trong một bài kiểm tra đơn vị khi bạn muốn xác minh rằng bạn không tạo ra rò rỉ bộ nhớ (ví dụ: nếu bạn đang làm gì đó với WeakReferences hoặc Cond điềuWeakTable, mã được tạo động, v.v.).

Ví dụ: tôi có một vài bài kiểm tra như:

WeakReference w = CodeThatShouldNotMemoryLeak();
Assert.IsTrue(w.IsAlive);
GC.Collect();
GC.WaitForPendingFinalizers();
Assert.IsFalse(w.IsAlive);

Có thể lập luận rằng việc sử dụng WeakReferences là một vấn đề trong chính nó, nhưng có vẻ như nếu bạn đang tạo một hệ thống dựa trên hành vi đó thì gọi GC.Collect () là một cách tốt để xác minh mã đó.




2
using(var stream = new MemoryStream())
{
   bitmap.Save(stream, ImageFormat.Png);
   techObject.Last().Image = Image.FromStream(stream);
   bitmap.Dispose();

   // Without this code, I had an OutOfMemory exception.
   GC.Collect();
   GC.WaitForPendingFinalizers();
   //
}

2

Có một số tình huống an toàn hơn là xin lỗi.

Đây là một tình huống.

Có thể tác giả một DLL không được quản lý trong C # bằng cách viết lại IL (vì có những tình huống cần thiết).

Bây giờ, giả sử, ví dụ, DLL tạo ra một mảng byte ở cấp độ lớp - bởi vì nhiều hàm được xuất cần truy cập như vậy. Điều gì xảy ra khi DLL được tải? Là người thu gom rác tự động được gọi tại thời điểm đó? Tôi không biết, nhưng là một DLL không được quản lý , hoàn toàn có thể là GC không được gọi. Và nó sẽ là một vấn đề lớn nếu nó không được gọi. Khi DLL được tải quá, đó cũng sẽ là trình thu gom rác - vậy ai sẽ chịu trách nhiệm thu thập bất kỳ rác nào có thể và họ sẽ làm như thế nào? Tốt hơn nên sử dụng công cụ thu gom rác của C #. Có chức năng dọn dẹp (có sẵn cho máy khách DLL) trong đó các biến cấp độ lớp được đặt thành null và trình thu gom rác được gọi.

Cẩn tắc vô ưu.


2

tôi vẫn không chắc chắn về điều này Tôi đang làm việc từ 7 năm trên Máy chủ ứng dụng. Cài đặt lớn hơn của chúng tôi sử dụng Ram 24 GB. Đa luồng rất cao và TẤT CẢ các cuộc gọi cho GC.Collect () gặp phải các vấn đề hiệu năng thực sự khủng khiếp.

Nhiều thành phần bên thứ ba đã sử dụng GC.Collect () khi họ nghĩ rằng thật thông minh để làm điều này ngay bây giờ. Vì vậy, một loạt các Báo cáo Excel đơn giản đã chặn Máy chủ ứng dụng cho tất cả các luồng vài lần một phút.

Chúng tôi đã phải cấu trúc lại tất cả các Thành phần của bên thứ 3 để loại bỏ các cuộc gọi GC.Collect () và tất cả đều hoạt động tốt sau khi thực hiện việc này.

Nhưng tôi cũng đang chạy Máy chủ trên Win32, và ở đây tôi bắt đầu sử dụng rất nhiều GC.Collect () sau khi nhận được OutOfMemoryException.

Nhưng tôi cũng không chắc lắm về điều này, vì tôi thường nhận thấy, khi tôi nhận được OOM trên 32 Bit và tôi thử chạy lại hoạt động tương tự, mà không gọi cho GC.Collect (), nó chỉ hoạt động tốt.

Một điều tôi tự hỏi là chính OOM Exception ... Nếu tôi đã viết .Net Framework và tôi không thể phân bổ một khối bộ nhớ, tôi sẽ sử dụng GC.Collect (), phân mảnh bộ nhớ (??), thử lại và nếu tôi vẫn không thể tìm thấy khối bộ nhớ trống, thì tôi sẽ ném OOM-Exception.

Hoặc ít nhất thực hiện hành vi này dưới dạng tùy chọn có thể định cấu hình, do những hạn chế của vấn đề hiệu năng với GC.Collect.

Bây giờ tôi có rất nhiều mã như thế này trong ứng dụng của mình để "giải quyết" vấn đề:

public static TResult ExecuteOOMAware<T1, T2, TResult>(Func<T1,T2 ,TResult> func, T1 a1, T2 a2)
{

    int oomCounter = 0;
    int maxOOMRetries = 10;
    do
    {
        try
        {
            return func(a1, a2);
        }
        catch (OutOfMemoryException)
        {
            oomCounter++;
            if (maxOOMRetries > 10)
            {
                throw;
            }
            else
            {
                Log.Info("OutOfMemory-Exception caught, Trying to fix. Counter: " + oomCounter.ToString());
                System.Threading.Thread.Sleep(TimeSpan.FromSeconds(oomCounter * 10));
                GC.Collect();
            }
        }
    } while (oomCounter < maxOOMRetries);

    // never gets hitted.
    return default(TResult);
}

(Lưu ý rằng hành vi Thread.S ngủ () là một hành vi ứng dụng thực sự của Ứng dụng, bởi vì chúng tôi đang chạy Dịch vụ lưu đệm ORM và dịch vụ phải mất một thời gian để giải phóng tất cả các đối tượng được lưu trong bộ nhớ cache, nếu RAM vượt quá một số giá trị được xác định trước. vài giây lần đầu tiên và đã tăng thời gian chờ đợi mỗi lần xuất hiện của OOM.)


Một thành phần không nên gọi GC.Collect. Vì nó có hiệu ứng rộng ứng dụng nên chỉ có ứng dụng nên làm như vậy (nếu có).
CodeInChaos

If i would have written the .Net Framework, and i can't alloc a memory block, i would use GC.Collect(),- Tôi nghĩ rằng họ đã làm điều này - Tôi đã thấy các dấu hiệu cho thấy một trong những kích hoạt GC bên trong là sự thất bại nhất định trong việc phân bổ bộ nhớ.
G. Stoynev

2

Bạn nên cố gắng tránh sử dụng GC.Collect () vì nó rất đắt. Đây là một ví dụ:

        public void ClearFrame(ulong timeStamp)
    {
        if (RecordSet.Count <= 0) return;
        if (Limit == false)
        {
            var seconds = (timeStamp - RecordSet[0].TimeStamp)/1000;
            if (seconds <= _preFramesTime) return;
            Limit = true;
            do
            {
                RecordSet.Remove(RecordSet[0]);
            } while (((timeStamp - RecordSet[0].TimeStamp) / 1000) > _preFramesTime);
        }
        else
        {
            RecordSet.Remove(RecordSet[0]);

        }
        GC.Collect(); // AVOID
    }

KẾT QUẢ KIỂM TRA: SỬ DỤNG CPU 12%

Khi bạn thay đổi điều này:

        public void ClearFrame(ulong timeStamp)
    {
        if (RecordSet.Count <= 0) return;
        if (Limit == false)
        {
            var seconds = (timeStamp - RecordSet[0].TimeStamp)/1000;
            if (seconds <= _preFramesTime) return;
            Limit = true;
            do
            {
                RecordSet[0].Dispose(); //  Bitmap destroyed!
                RecordSet.Remove(RecordSet[0]);
            } while (((timeStamp - RecordSet[0].TimeStamp) / 1000) > _preFramesTime);
        }
        else
        {
            RecordSet[0].Dispose(); //  Bitmap destroyed!
            RecordSet.Remove(RecordSet[0]);

        }
        //GC.Collect();
    }

KẾT QUẢ KIỂM TRA: SỬ DỤNG CPU 2-3%


1

Một lý do khác là khi bạn mở Cổng nối tiếp trên cổng USB COM và sau đó rút thiết bị USB. Vì Cổng nối tiếp đã được mở, tài nguyên giữ tham chiếu đến cổng được kết nối trước đó trong sổ đăng ký của hệ thống. Đăng ký của hệ thống sau đó sẽ chứa dữ liệu cũ , vì vậy danh sách các cổng khả dụng sẽ bị sai. Do đó cổng phải được đóng lại.

Gọi SerialPort.Close () trên cổng gọi Dispose () trên đối tượng, nhưng nó vẫn còn trong bộ nhớ cho đến khi bộ sưu tập rác thực sự chạy, khiến cho registry vẫn bị cũ cho đến khi trình thu gom rác quyết định giải phóng tài nguyên.

Từ https://stackoverflow.com/a/58810699/8685342 :

try
{
    if (port != null)
        port.Close(); //this will throw an exception if the port was unplugged
}
catch (Exception ex) //of type 'System.IO.IOException'
{
    System.GC.Collect();
    System.GC.WaitForPendingFinalizers();
}

port = null;

0

Điều này không liên quan đến câu hỏi, nhưng đối với các biến đổi XSLT trong .NET (XSLCompiledTranform) thì bạn có thể không có lựa chọn nào khác. Một ứng cử viên khác là kiểm soát MSHTML.



0

một lý do chính đáng để gọi GC là trên các máy tính ARM nhỏ có bộ nhớ nhỏ, như Raspberry PI (chạy với đơn âm). Nếu các đoạn bộ nhớ chưa được phân bổ sử dụng quá nhiều RAM hệ thống, thì HĐH Linux có thể không ổn định. Tôi có một ứng dụng mà tôi phải gọi cho GC mỗi giây (!) Để thoát khỏi các vấn đề tràn bộ nhớ.

Một giải pháp tốt khác là vứt bỏ đồ vật khi chúng không còn cần thiết. Thật không may, điều này không dễ dàng như vậy trong nhiều trường hợp.


0

Vì có đống đối tượng nhỏ (SOH) và đống đối tượng lớn (LOH)

Chúng ta có thể gọi GC.Collect () để xóa đối tượng khử tham chiếu trong SOP và chuyển đối tượng sống sang thế hệ tiếp theo.

Trong .net4.5, chúng tôi cũng có thể nén LOH bằng cách sử dụng bigobjectheapcompactionmode


0

Nếu bạn đang tạo nhiều System.Drawing.Bitmapđối tượng mới , Garbage Collector sẽ không xóa chúng. Cuối cùng, GDI + sẽ nghĩ rằng bạn sắp hết bộ nhớ và sẽ đưa ra một ngoại lệ "Tham số không hợp lệ". Gọi GC.Collect()thường xuyên (không quá thường xuyên!) Dường như để giải quyết vấn đề này.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.