Khi nào thì nên thu gom rác?


135

Vì vậy, tôi đã đọc một câu hỏi về việc buộc trình thu gom rác C # chạy trong đó hầu hết mọi câu trả lời đều giống nhau: bạn có thể làm điều đó, nhưng bạn không nên - ngoại trừ một số trường hợp rất hiếm . Đáng buồn thay, không có ai ở đó giải thích về những trường hợp như vậy.

Bạn có thể cho tôi biết trong trường hợp nào nó thực sự là một ý tưởng tốt hoặc hợp lý để buộc thu gom rác?

Tôi không yêu cầu các trường hợp cụ thể của C # mà thay vào đó, tất cả các ngôn ngữ lập trình có trình thu gom rác. Tôi biết rằng bạn không thể ép buộc tất cả các ngôn ngữ, như Java, nhưng giả sử bạn có thể.


17
"nhưng đúng hơn, tất cả các ngôn ngữ lập trình có trình thu gom rác" Các ngôn ngữ khác nhau (hoặc, đúng hơn là các cách triển khai khác nhau ) sử dụng các phương pháp khác nhau để thu gom rác, do đó bạn không thể tìm thấy quy tắc một kích cỡ phù hợp cho tất cả.
Đại tá Ba mươi Hai

4
@Doval Nếu bạn bị ràng buộc theo thời gian thực và GC không cung cấp bảo đảm phù hợp, bạn sẽ ở giữa một tảng đá và một nơi khó khăn. Nó có thể giảm tạm dừng không mong muốn so với không làm gì, nhưng từ những gì tôi nghe được thì "dễ dàng" hơn để tránh phân bổ trong quá trình hoạt động bình thường.

3
Tôi có ấn tượng rằng nếu bạn đang mong đợi có thời hạn thực tế khó khăn, bạn sẽ không bao giờ sử dụng ngôn ngữ GC ở nơi đầu tiên.
GregRos 17/03/2015

4
Tôi không thể thấy cách bạn có thể trả lời câu hỏi này theo cách không dành riêng cho VM. Có liên quan đến các quy trình 32 bit, không liên quan đến các quy trình 64 bit. NET JVMcho cao cấp một
rwong

3
@DavidConrad bạn có thể buộc nó trong C #. Do đó câu hỏi.
Omega

Câu trả lời:


127

Bạn thực sự không thể đưa ra tuyên bố về cách thích hợp để sử dụng tất cả các triển khai GC. Họ khác nhau rất nhiều. Vì vậy, tôi sẽ nói chuyện với .NET mà bạn đã đề cập ban đầu.

Bạn phải biết hành vi của GC khá thân mật để làm điều này với bất kỳ logic hoặc lý do.

Lời khuyên duy nhất về bộ sưu tập tôi có thể đưa ra là: Đừng bao giờ làm điều đó.

Nếu bạn thực sự biết các chi tiết phức tạp của GC, bạn sẽ không cần lời khuyên của tôi nên điều đó không thành vấn đề. Nếu bạn chưa biết với độ tin cậy 100% thì nó sẽ có ích, và phải tìm kiếm trực tuyến và tìm câu trả lời như thế này: Bạn không nên gọi cho GC.Collect , hoặc cách khác: Bạn nên tìm hiểu chi tiết về cách thức hoạt động của GC từ trong ra ngoài, và chỉ sau đó bạn mới biết câu trả lời .

Có một nơi an toàn, có ý nghĩa khi sử dụng GC.Collect :

GC.Collect là một API có sẵn mà bạn có thể sử dụng để định hình thời gian của mọi thứ. Bạn có thể lập hồ sơ một thuật toán, thu thập và lập hồ sơ một thuật toán khác ngay sau đó khi biết GC của thuật toán đầu tiên không xảy ra trong lần thứ hai của bạn làm sai lệch kết quả.

Kiểu hồ sơ này là lần duy nhất tôi từng đề nghị thu thập thủ công cho bất kỳ ai.


Dù sao đi nữa

Một trường hợp sử dụng có thể là nếu bạn tải những thứ thực sự lớn, chúng sẽ kết thúc trong Heap đối tượng lớn sẽ đi thẳng đến Gen 2, mặc dù vậy, Gen 2 lại dành cho các đối tượng tồn tại lâu vì nó thu thập ít thường xuyên hơn. Nếu bạn biết rằng bạn đang tải các đối tượng tồn tại ngắn vào Gen 2 vì bất kỳ lý do gì, bạn có thể xóa chúng nhanh hơn để giữ cho Gen 2 của bạn nhỏ hơn và bộ sưu tập của nó nhanh hơn.

Đây là ví dụ tốt nhất tôi có thể đưa ra, và nó không tốt - áp lực LOH mà bạn xây dựng ở đây sẽ gây ra các bộ sưu tập thường xuyên hơn và các bộ sưu tập thường xuyên như vậy - rất có thể nó sẽ xóa LOH giống như nhanh như bạn đã thổi nó ra với các đối tượng tạm thời. Tôi chỉ đơn giản là không tin tưởng bản thân mình để đoán một tần số bộ sưu tập tốt hơn so với GC bản thân - điều chỉnh bởi những người xa xa thông minh hơn I.


Vì vậy, hãy nói về một số ngữ nghĩa và cơ chế trong .NET GC ... hoặc ..

Tất cả mọi thứ tôi nghĩ rằng tôi biết về .NET GC

Xin vui lòng, bất cứ ai tìm thấy lỗi ở đây - hãy sửa cho tôi. Phần lớn các GC được biết đến là ma thuật đen và trong khi tôi cố gắng bỏ qua các chi tiết mà tôi không chắc chắn, tôi có lẽ vẫn còn một số điều sai.

Dưới đây là cố tình thiếu rất nhiều chi tiết tôi không chắc chắn, cũng như một lượng thông tin lớn hơn nhiều mà tôi chỉ đơn giản là không biết. Sử dụng thông tin này có nguy cơ của riêng bạn.


Khái niệm GC

.NET GC xảy ra vào những thời điểm không nhất quán, đó là lý do tại sao nó được gọi là "không xác định", điều này có nghĩa là bạn không thể dựa vào nó để xảy ra vào những thời điểm cụ thể. Nó cũng là một trình thu gom rác thế hệ, có nghĩa là nó phân vùng các đối tượng của bạn thành số lượng GC mà chúng đã trải qua.

Các đối tượng trong heap Gen 0 đã sống qua 0 bộ sưu tập, chúng đã được tạo mới nên gần đây không có bộ sưu tập nào xảy ra kể từ khi khởi tạo. Các đối tượng trong heap Gen 1 của bạn đã sống qua một lần thu thập và các đối tượng tương tự trong heap Gen 2 của bạn đã sống qua 2 lần thu thập.

Bây giờ đáng chú ý là lý do nó đủ điều kiện cho các thế hệ và phân vùng cụ thể phù hợp. .NET GC chỉ nhận ra ba thế hệ này, bởi vì bộ sưu tập vượt qua ba đống này hoàn toàn khác nhau. Một số đối tượng có thể sống sót qua bộ sưu tập hàng ngàn lần. GC chỉ để những thứ này ở phía bên kia của phân vùng heap Gen 2, không có điểm nào trong việc phân vùng chúng ở bất cứ đâu xa hơn vì chúng thực sự là Gen 44; bộ sưu tập vượt qua chúng giống như mọi thứ trong đống gen 2.

Có những mục đích ngữ nghĩa cho các thế hệ cụ thể này, cũng như các cơ chế được thực hiện nhằm tôn vinh những thế hệ này và tôi sẽ đến với những người đó ngay lập tức.


Những gì trong một bộ sưu tập

Khái niệm cơ bản của một bộ sưu tập GC là nó kiểm tra từng đối tượng trong một không gian heap để xem liệu vẫn còn các tham chiếu trực tiếp (gốc GC) cho các đối tượng này hay không. Nếu một gốc GC được tìm thấy cho một đối tượng, điều đó có nghĩa là mã hiện đang thực thi vẫn có thể tiếp cận và sử dụng đối tượng đó, vì vậy nó không thể bị xóa. Tuy nhiên, nếu không tìm thấy gốc GC cho một đối tượng, điều đó có nghĩa là quá trình đang chạy không còn cần đối tượng nữa, vì vậy nó có thể loại bỏ nó để giải phóng bộ nhớ cho các đối tượng mới.

Bây giờ sau khi hoàn thành việc dọn dẹp một loạt các vật thể và để lại một mình, sẽ có một tác dụng phụ đáng tiếc: Khoảng cách không gian trống giữa các vật thể sống nơi những người chết đã được gỡ bỏ. Sự phân mảnh bộ nhớ này nếu chỉ để lại một mình sẽ làm lãng phí bộ nhớ, do đó, các bộ sưu tập thường sẽ thực hiện cái gọi là "nén" trong đó chúng lấy tất cả các vật thể còn lại và ép chúng lại với nhau trong một đống để bộ nhớ trống nằm liền kề ở một bên của đống cho Gen 0.

Bây giờ được đưa ra ý tưởng về 3 đống bộ nhớ, tất cả được phân chia theo số lượng bộ sưu tập họ đã trải qua, hãy nói về lý do tại sao các phân vùng này tồn tại.


Bộ sưu tập Gen 0

Gen 0 là đối tượng mới nhất tuyệt đối, có xu hướng rất nhỏ - vì vậy bạn có thể thu thập nó rất thường xuyên . Tần suất đảm bảo heap vẫn nhỏ và các bộ sưu tập rất nhanh vì chúng thu thập trên một đống nhỏ như vậy. Điều này dựa trên ít nhiều dựa trên một heuristic tuyên bố: Phần lớn các đối tượng tạm thời mà bạn tạo ra là rất tạm thời, do đó tạm thời chúng sẽ không còn được sử dụng hoặc tham chiếu gần như ngay lập tức sau khi sử dụng và do đó có thể được thu thập.


Bộ sưu tập Gen 1

Gen 1 là các đối tượng không thuộc loại đối tượng rất tạm thời này, có thể vẫn còn tồn tại khá ngắn, bởi vì - một phần lớn các đối tượng được tạo ra không được sử dụng lâu dài. Do đó, Gen 1 cũng thu thập khá thường xuyên, một lần nữa giữ cho nó rất nhỏ để bộ sưu tập của nó nhanh. Tuy nhiên, giả định ít đối tượng của nó là tạm thời hơn Gen 0, do đó, nó thu thập ít thường xuyên hơn Gen 0

Tôi sẽ nói rằng tôi thực sự không biết các cơ chế kỹ thuật khác nhau giữa bộ sưu tập của Gen 0 và của Gen 1, nếu có bất kỳ thứ gì khác ngoài tần số chúng thu thập.


Bộ sưu tập Gen 2

Gen 2 bây giờ phải là mẹ của tất cả các đống phải không? Vâng, vâng, điều đó ít nhiều đúng. Đó là nơi tất cả các đối tượng vĩnh viễn của bạn sống - Main()ví dụ như đối tượng mà bạn sống và mọi thứ Main()tham chiếu bởi vì những đối tượng đó sẽ được bắt nguồn cho đến khi bạn Main()quay trở lại vào cuối quá trình.

Cho rằng Gen 2 là một cái xô cho tất cả mọi thứ mà các thế hệ khác không thể thu thập được, các đối tượng của nó phần lớn là vĩnh viễn hoặc ít nhất là tồn tại lâu dài. Vì vậy, nhận ra rất ít những gì trong Gen 2 thực sự sẽ là thứ có thể được thu thập, nó không cần phải thu thập thường xuyên. Điều này cho phép bộ sưu tập của nó cũng chậm hơn, vì nó thực hiện rất ít thường xuyên hơn. Vì vậy, về cơ bản, đây là nơi họ đã giải quyết tất cả các hành vi bổ sung cho các tình huống kỳ lạ, bởi vì họ có thời gian để thực hiện chúng.


Đống vật thể lớn

Một ví dụ về các hành vi bổ sung của Gen 2 là nó cũng thực hiện bộ sưu tập trên Heap đối tượng lớn. Cho đến bây giờ tôi đã nói hoàn toàn về Heap đối tượng nhỏ, nhưng thời gian chạy .NET phân bổ những thứ có kích thước nhất định cho một heap riêng vì những gì tôi gọi là nén ở trên. Nén yêu cầu di chuyển các đối tượng xung quanh khi các bộ sưu tập kết thúc trên Heap đối tượng nhỏ. Nếu có một đối tượng 10mb còn sống trong Gen 1, thì sẽ mất nhiều thời gian hơn để hoàn thành việc nén sau khi thu thập, do đó làm chậm bộ sưu tập của Gen 1. Vì vậy, đối tượng 10mb được phân bổ cho Heap đối tượng lớn và được thu thập trong Gen 2 chạy không thường xuyên.


Hoàn thiện

Một ví dụ khác là các đối tượng với quyết toán. Bạn đặt một bộ hoàn thiện vào một đối tượng tham chiếu các tài nguyên nằm ngoài phạm vi của .NETs (tài nguyên không được quản lý). Trình hoàn thiện là cách duy nhất mà GC yêu cầu thu thập tài nguyên không được quản lý - bạn triển khai trình hoàn thiện của mình để thực hiện thu thập / xóa / giải phóng tài nguyên không được quản lý để đảm bảo nó không bị rò rỉ từ quy trình của bạn. Khi GC thực hiện bộ hoàn thiện đối tượng của bạn, thì việc triển khai của bạn sẽ xóa tài nguyên không được quản lý, làm cho GC có khả năng loại bỏ đối tượng của bạn mà không gặp rủi ro rò rỉ tài nguyên.

Cơ chế mà người hoàn thiện thực hiện điều này là bằng cách được tham chiếu trực tiếp trong hàng đợi quyết toán. Khi bộ thực thi phân bổ một đối tượng với bộ hoàn thiện, nó sẽ thêm một con trỏ tới đối tượng đó vào hàng đợi hoàn thiện và khóa đối tượng của bạn tại chỗ (được gọi là ghim) để nén không di chuyển nó sẽ phá vỡ tham chiếu hàng đợi quyết toán. Khi bộ sưu tập xảy ra, cuối cùng đối tượng của bạn sẽ không còn có gốc GC nữa, nhưng việc hoàn thiện phải được thực hiện trước khi có thể được thu thập. Vì vậy, khi đối tượng đã chết, bộ sưu tập sẽ di chuyển tham chiếu của nó từ hàng đợi hoàn thiện và đặt một tham chiếu đến nó trên hàng đợi được gọi là "FReachable". Sau đó bộ sưu tập tiếp tục. Tại một thời điểm "không xác định" khác trong tương lai, một luồng riêng biệt được gọi là luồng Finalizer sẽ đi qua hàng đợi FReachable, thực thi các trình hoàn thiện cho từng đối tượng được tham chiếu. Sau khi kết thúc, hàng đợi FReachable trống và nó đã lật một chút trên tiêu đề của từng đối tượng nói rằng họ không cần hoàn thiện (Bit này cũng có thể được lật bằng tay vớiGC.SuppressFinalizevốn phổ biến trong Dispose()các phương thức), tôi cũng nghi ngờ nó đã bỏ ghim các đối tượng, nhưng đừng trích dẫn tôi về điều đó. Bộ sưu tập tiếp theo xuất hiện trên bất kỳ đống vật thể nào trong đó, cuối cùng sẽ thu thập nó. Các bộ sưu tập Gen 0 thậm chí không chú ý đến các đối tượng có bit cần thiết quyết toán đó, nó tự động quảng bá chúng mà không cần kiểm tra gốc của chúng. Một đối tượng chưa được phân phối cần hoàn thiện trong Gen 1, sẽ bị ném vào FReachablehàng đợi, nhưng bộ sưu tập không làm gì khác với nó, vì vậy, nó sống trong Gen 2. Theo cách này, tất cả các đối tượng có bộ hoàn thiện và không GC.SuppressFinalizesẽ được thu thập trong Gen 2.


4
@FlorianMargaine yeah ... nói bất cứ điều gì về "GC" trong tất cả các triển khai thực sự không có ý nghĩa ..
Jimmy Hoffa

10
tl; dr: Sử dụng nhóm đối tượng thay thế.
Robert Harvey

5
tl; dr: Đối với thời gian / hồ sơ, nó có thể hữu ích.
kutschkem 18/03/2015

3
@Den sau khi đọc mô tả của tôi ở trên về cơ học (theo tôi hiểu chúng), lợi ích như bạn thấy là gì? Bạn dọn sạch một số lượng lớn các đối tượng - trong SOH (hoặc LOH?)? Bạn vừa khiến các chủ đề khác tạm dừng cho bộ sưu tập này? Có phải bộ sưu tập đó đã quảng bá gấp đôi số đối tượng cho Gen 2 khi nó bị xóa? Bộ sưu tập có gây ra sự nén trên LOH (bạn đã bật nó chưa?)? Bạn có bao nhiêu đống GC và là GC của bạn ở chế độ máy chủ hoặc máy tính để bàn? GC là một tảng băng của feckin, sự phản bội nằm dưới vùng nước. Chỉ cần lái rõ ràng. Tôi không đủ thông minh để thoải mái thu thập.
Jimmy Hoffa

4
Nhóm đối tượng @RobertHarvey cũng không phải là viên đạn bạc. Thế hệ 0 của trình thu gom rác đã thực sự là một nhóm đối tượng - nó thường có kích thước phù hợp với mức bộ nhớ cache nhỏ nhất và do đó, các đối tượng mới thường được tạo trong bộ nhớ đã có trong bộ đệm. Nhóm đối tượng của bạn hiện đang cạnh tranh với vườn ươm của GC cho bộ đệm và nếu tổng của vườn ươm của GC và nhóm của bạn lớn hơn bộ đệm thì rõ ràng bạn sẽ bị mất bộ nhớ cache. Và nếu bạn có kế hoạch sử dụng song song bây giờ, bạn phải thực hiện lại đồng bộ hóa và lo lắng về việc chia sẻ sai.
Doval

68

Đáng buồn thay, không có ai ở đó giải thích về những trường hợp như vậy.

Tôi sẽ đưa ra một số ví dụ. Nói chung, rất hiếm khi ép buộc một GC là một ý tưởng tốt nhưng nó có thể hoàn toàn xứng đáng. Câu trả lời này là từ kinh nghiệm của tôi với văn học .NET và GC. Nó nên khái quát tốt cho các nền tảng khác (ít nhất là những nền tảng có GC đáng kể).

  • Điểm chuẩn của các loại. Bạn muốn một trạng thái heap được quản lý đã biết khi điểm chuẩn bắt đầu để GC không kích hoạt ngẫu nhiên trong điểm chuẩn. Khi bạn lặp lại một điểm chuẩn, bạn muốn có cùng số lượng và số lượng công việc GC trong mỗi lần lặp lại.
  • Phát hành tài nguyên đột ngột. Ví dụ: đóng một cửa sổ GUI quan trọng hoặc làm mới bộ đệm (và do đó giải phóng nội dung bộ đệm cũ có khả năng lớn). GC không thể phát hiện ra điều này bởi vì tất cả những gì bạn đang làm là đặt tham chiếu thành null. Thực tế là điều này mồ côi toàn bộ đồ thị đối tượng không dễ phát hiện.
  • Phát hành các tài nguyên không được quản lý đã bị rò rỉ . Tất nhiên, điều này không bao giờ xảy ra, nhưng tôi đã thấy các trường hợp thư viện bên thứ 3 bị rò rỉ nội dung (chẳng hạn như các đối tượng COM). Các nhà phát triển đã buộc phải đôi khi tạo ra một bộ sưu tập.
  • Các ứng dụng tương tác như trò chơi . Trong khi chơi trò chơi có ngân sách thời gian rất nghiêm ngặt trên mỗi khung hình (60Hz => 16ms mỗi khung hình). Để tránh bị mắc kẹt, bạn cần có một chiến lược để đối phó với các GC. Một chiến lược như vậy là trì hoãn các G2 G2 càng nhiều càng tốt và buộc chúng vào một thời điểm thích hợp như màn hình tải hoặc cảnh bị cắt. Các GC không thể biết khi nào thời điểm tốt nhất như vậy là.
  • Kiểm soát độ trễ nói chung. Một số ứng dụng web vô hiệu hóa các GC và định kỳ chạy bộ sưu tập G2 trong khi bị tắt khỏi vòng quay cân bằng tải. Bằng cách đó, độ trễ G2 không bao giờ xuất hiện đối với người dùng.

Nếu mục tiêu của bạn là thông lượng thì càng hiếm thì càng tốt. Trong những trường hợp đó, việc buộc một bộ sưu tập không thể có tác động tích cực (ngoại trừ các vấn đề khá khó khăn như tăng sử dụng bộ đệm CPU bằng cách loại bỏ các đối tượng chết xen kẽ trong các đối tượng sống). Bộ sưu tập hàng loạt là hiệu quả hơn cho tất cả các nhà sưu tập tôi biết. Đối với ứng dụng sản xuất trong tiêu thụ bộ nhớ ở trạng thái ổn định, việc tạo ra một GC không giúp ích gì.

Các ví dụ đưa ra ở trên mục tiêu nhất quán và giới hạn của việc sử dụng bộ nhớ. Trong những trường hợp gây ra GC có thể có ý nghĩa.

Dường như có một ý tưởng phổ biến rộng rãi rằng GC là một thực thể thiêng liêng tạo ra một bộ sưu tập bất cứ khi nào nó thực sự tối ưu để làm như vậy. Không có GC tôi biết là tinh vi và thực sự rất khó để tối ưu cho GC. GC biết ít hơn nhà phát triển. Các heuristic dựa trên bộ đếm bộ nhớ và những thứ như tốc độ thu thập, v.v. Các heuristic thường tốt nhưng chúng không nắm bắt được những thay đổi đột ngột trong hành vi ứng dụng như giải phóng một lượng lớn bộ nhớ được quản lý. Nó cũng mù quáng đối với các tài nguyên không được quản lý và các yêu cầu về độ trễ.

Lưu ý, chi phí GC thay đổi theo kích thước heap và số lượng tài liệu tham khảo trên heap. Trên một đống nhỏ, chi phí có thể rất nhỏ. Tôi đã thấy tốc độ thu thập G2 với .NET 4.5 là 1-2GB / giây trên một ứng dụng sản xuất với kích thước heap 1GB.


Đối với trường hợp kiểm soát độ trễ, tôi đoán thay vì thực hiện việc này định kỳ, bạn cũng có thể thực hiện theo nhu cầu (nghĩa là khi mức sử dụng bộ nhớ tăng lên trên một ngưỡng nhất định).
Paŭlo Ebermann

3
+1 cho đoạn thứ hai đến đoạn cuối. Một số người có cùng quan điểm về trình biên dịch và nhanh chóng gọi hầu hết mọi thứ là "tối ưu hóa sớm". Tôi thường nói với họ một cái gì đó tương tự.
Honza Brabec

2
+1 cho đoạn đó là tốt. Tôi thấy thật sốc khi mọi người nghĩ rằng một chương trình máy tính được viết bởi người khác nhất thiết phải hiểu các đặc tính hiệu suất của chương trình của họ tốt hơn chính họ.
Mehrdad

1
@HonzaBrabec Vấn đề là giống nhau trong cả hai trường hợp: Nếu bạn nghĩ rằng bạn biết rõ hơn so với GC hoặc trình biên dịch, thì rất dễ làm tổn thương chính bạn. Nếu bạn thực sự biết nhiều hơn, thì bạn chỉ tối ưu hóa khi bạn biết rằng nó không còn sớm.
Svick

27

Theo nguyên tắc chung, trình thu gom rác sẽ thu thập khi nó gặp "áp lực bộ nhớ" và được coi là không nên thu thập vào lúc khác vì bạn có thể gây ra sự cố về hiệu suất hoặc thậm chí tạm dừng đáng chú ý trong quá trình thực thi chương trình của mình. Và trên thực tế, điểm đầu tiên phụ thuộc vào điểm thứ hai: đối với người thu gom rác thế hệ, ít nhất, nó chạy càng hiệu quả thì tỷ lệ rác với các đối tượng tốt càng cao, do đó , để giảm thiểu thời gian tạm dừng chương trình , nó phải chần chừ và để rác chất đống càng nhiều càng tốt.

Sau đó, thời điểm thích hợp để gọi trình thu gom rác theo cách thủ công là khi bạn hoàn thành việc gì đó mà 1) có thể đã tạo ra rất nhiều rác và người dùng dự kiến ​​sẽ mất một thời gian và khiến hệ thống không phản hồi dù sao. Một ví dụ kinh điển là ở cuối tải một cái gì đó lớn (tài liệu, mô hình, cấp độ mới, v.v.)


12

Một điều không ai đã đề cập là, trong khi Windows GC tốt đến mức đáng kinh ngạc, thì GC trên Xbox lại là rác rưởi (ý định chơi chữ) .

Vì vậy, khi mã hóa một trò chơi XNA dự định chạy trên XBox, việc thu gom rác thời gian đến những thời điểm thích hợp là vô cùng quan trọng, hoặc bạn sẽ có những trục trặc FPS gián đoạn khủng khiếp. Ngoài ra, trên XBox, thông thường sử dụng structcách của bạn, cách thường xuyên hơn bạn thường làm, để giảm thiểu số lượng đối tượng cần thu gom rác.


4

Bộ sưu tập rác trước hết là một công cụ quản lý bộ nhớ. Như vậy, người thu gom rác sẽ thu gom khi có áp lực bộ nhớ.

Công cụ thu gom rác hiện đại rất tốt và ngày càng tốt hơn, do đó bạn không thể cải thiện chúng bằng cách thu gom thủ công. Ngay cả khi bạn có thể cải thiện mọi thứ ngày hôm nay, thì cũng có thể là một cải tiến trong tương lai cho trình thu gom rác đã chọn của bạn sẽ làm cho việc tối ưu hóa của bạn không hiệu quả, hoặc thậm chí phản tác dụng.

Tuy nhiên , người thu gom rác thường không cố gắng tối ưu hóa việc sử dụng các tài nguyên khác ngoài bộ nhớ. Trong các môi trường được thu gom rác, hầu hết các tài nguyên không có bộ nhớ có giá trị đều có một closephương thức hoặc tương tự, nhưng có một số trường hợp không phải là trường hợp vì một số lý do, chẳng hạn như khả năng tương thích với API hiện có.

Trong những trường hợp này, có thể có ý nghĩa khi gọi thủ công bộ sưu tập rác khi bạn biết rằng tài nguyên không có bộ nhớ có giá trị đang được sử dụng.

RMI

Một ví dụ cụ thể về điều này là Gọi phương thức từ xa của Java. RMI là một thư viện cuộc gọi thủ tục từ xa. Bạn thường có một máy chủ, làm cho các đối tượng khác nhau có sẵn để khách hàng sử dụng. Nếu một máy chủ biết rằng một đối tượng không được sử dụng bởi bất kỳ khách hàng nào, thì đối tượng đó đủ điều kiện để thu gom rác.

Tuy nhiên, cách duy nhất mà máy chủ biết điều này là nếu máy khách nói với nó và máy khách chỉ nói với máy chủ rằng nó không cần đối tượng nữa một khi máy khách đã thu gom rác bất cứ thứ gì đang sử dụng.

Điều này trình bày một vấn đề, vì máy khách có thể có rất nhiều bộ nhớ trống, do đó có thể không chạy bộ sưu tập rác rất thường xuyên. Trong khi đó, máy chủ có thể có rất nhiều đối tượng không được sử dụng trong bộ nhớ mà nó không thể thu thập được vì không biết rằng máy khách không sử dụng chúng.

Giải pháp trong RMI là cho máy khách chạy bộ sưu tập rác định kỳ, ngay cả khi nó có nhiều bộ nhớ, để đảm bảo rằng các đối tượng được thu thập kịp thời trên máy chủ.


"Trong những trường hợp này, có thể có ý nghĩa khi gọi thủ công bộ sưu tập rác khi bạn biết rằng tài nguyên không phải bộ nhớ có giá trị đang được sử dụng" - nếu tài nguyên không có bộ nhớ đang được sử dụng, bạn nên sử dụng một usingkhối hoặc gọi Closephương thức khác đảm bảo tài nguyên bị loại bỏ càng sớm càng tốt. Dựa vào GC để dọn sạch các tài nguyên không có bộ nhớ là không đáng tin cậy và gây ra tất cả các loại sự cố (đặc biệt là với các tệp cần được khóa để truy cập nên chỉ có thể được mở một lần).
Jules

Và như đã nêu trong câu trả lời, khi một closephương thức có sẵn (hoặc tài nguyên có thể được sử dụng với một usingkhối), đây là những cách tiếp cận đúng. Câu trả lời đặc biệt liên quan đến các trường hợp hiếm hoi khi các cơ chế này không có sẵn.
James_pic

Ý kiến ​​cá nhân của tôi là bất kỳ giao diện nào quản lý tài nguyên không có bộ nhớ nhưng không cung cấp phương thức đóng là giao diện không nên được sử dụng , bởi vì không có cách nào để sử dụng nó một cách đáng tin cậy.
Jules

@ Tôi đồng ý, nhưng đôi khi không thể tránh khỏi. Đôi khi trừu tượng rò rỉ, và sử dụng trừu tượng rò rỉ tốt hơn là không sử dụng trừu tượng hóa. Đôi khi bạn cần phải làm việc với mã kế thừa yêu cầu bạn thực hiện những lời hứa mà bạn biết bạn không thể giữ. Vâng, rất hiếm, và nên tránh nếu có thể, và có một lý do là có tất cả những cảnh báo này xung quanh việc buộc phải thu gom rác, nhưng những tình huống này xuất hiện và OP đã hỏi những tình huống này trông như thế nào - mà tôi đã trả lời .
James_pic

2

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. .

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à một 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 " Các mẩu tin hiệu suất của Rico Mariani "


2

Có một số trường hợp bạn có thể muốn gọi gc () cho mình.

  • [ Một số người nói rằng điều này không tốt vì nó có thể thúc đẩy các đối tượng lên không gian thế hệ cũ mà tôi đồng ý không phải là một điều tốt. Tuy nhiên, KHÔNG phải lúc nào cũng đúng là sẽ luôn có những đối tượng có thể được thăng cấp. Chắc chắn là có thể sau gc()cuộc gọi này , rất ít đối tượng vẫn còn một mình được chuyển vào không gian thế hệ cũ ] Khi bạn sẽ tạo ra một bộ sưu tập lớn các đối tượng và sử dụng nhiều bộ nhớ. Bạn chỉ đơn giản muốn dọn dẹp càng nhiều không gian càng chuẩn bị càng tốt. Đây chỉ là lẽ thường. Bằng cách gọi gc()thủ công, sẽ không có kiểm tra biểu đồ tham chiếu dự phòng trên một phần của bộ sưu tập lớn các đối tượng mà bạn đang tải vào bộ nhớ. Nói tóm lại, nếu bạn chạy gc()trước khi tải nhiều vào bộ nhớ,gc() gây ra trong quá trình tải xảy ra ít nhất một lần khi tải bắt đầu tạo áp suất bộ nhớ.
  • Khi bạn đã tải xong một bộ sưu tập lớnlớncác đối tượng và bạn sẽ không thể tải thêm các đối tượng vào bộ nhớ. Nói tóm lại, bạn chuyển từ tạo pha sang sử dụng pha. Bằng cách gọi gc()tùy thuộc vào việc thực hiện, bộ nhớ được sử dụng sẽ được nén để cải thiện ồ ạt bộ nhớ cache. Điều này sẽ dẫn đến cải thiện lớn về hiệu suất mà bạn sẽ không nhận được từ hồ sơ .
  • Tương tự như cái đầu tiên, nhưng theo quan điểm rằng nếu bạn làm gc()và việc triển khai quản lý bộ nhớ hỗ trợ, bạn sẽ tạo ra sự liên tục tốt hơn nhiều cho bộ nhớ vật lý của bạn. Điều này một lần nữa làm cho bộ sưu tập lớn các đối tượng mới liên tục và gọn hơn, từ đó cải thiện hiệu suất

1
Ai đó có thể chỉ ra lý do của downvote? Bản thân tôi không biết đủ để đánh giá câu trả lời (thoạt nhìn nó có ý nghĩa với tôi).
Omega

1
Tôi đoán bạn có một downvote cho điểm thứ ba. Có khả năng cũng để nói "Đây chỉ là lẽ thường".
Immibis 18/03/2015

2
Khi bạn tạo một bộ sưu tập lớn đối tượng, GC phải đủ thông minh để biết rằng cần phải có một bộ sưu tập. Tương tự khi bộ nhớ cần được nén. Dựa vào GC để tối ưu hóa vị trí bộ nhớ của các đối tượng liên quan dường như không thể thực hiện được. Tôi nghĩ bạn có thể tìm các giải pháp khác (struct, không an toàn, ...). (Tôi không phải là người downvoter).
Guillaume

3
Ý tưởng đầu tiên của bạn về một thời gian ok chỉ là lời khuyên tồi trong quan điểm của tôi. Rất có thể gần đây đã có một bộ sưu tập vì vậy nỗ lực của bạn trong việc thu thập lại chỉ đơn giản là tự ý quảng bá các đối tượng cho các thế hệ sau, điều này hầu như luôn luôn xấu. Các thế hệ sau này có các bộ sưu tập mất nhiều thời gian hơn để bắt đầu, tăng kích thước heap của họ "để dọn sạch càng nhiều không gian càng tốt" chỉ khiến vấn đề này trở nên rắc rối hơn. Ngoài ra, nếu bạn sắp tăng áp lực bộ nhớ với tải, bạn có thể sẽ bắt đầu tạo ra các bộ sưu tập, điều này sẽ chạy chậm hơn vì tăng Gen1 / 2
Jimmy Hoffa

2
By calling gc() depending on implementation, the memory in used will be compacted which massively improves cache locality. This will result in massive improve in performance that you will not get from profiling.Nếu bạn phân bổ một tấn đối tượng theo tỷ lệ cược liên tiếp thì chúng đã được nén. Nếu bất cứ điều gì, bộ sưu tập rác có thể xáo trộn chúng xung quanh một chút. Dù bằng cách nào, việc sử dụng các cấu trúc dữ liệu dày đặc và không nhảy ngẫu nhiên trong bộ nhớ sẽ có tác động lớn hơn. Nếu bạn đang sử dụng danh sách liên kết một yếu tố trên mỗi nút ngây thơ, sẽ không có số lượng thủ thuật GC thủ công nào bù đắp cho điều đó.
Doval

2

Một ví dụ thực tế:

Tôi đã có một ứng dụng web sử dụng một tập hợp dữ liệu rất lớn hiếm khi thay đổi và cần được truy cập rất nhanh (đủ nhanh để phản hồi trên mỗi lần nhấn phím thông qua AJAX).

Điều rõ ràng đủ để làm ở đây là tải biểu đồ liên quan vào bộ nhớ và truy cập nó từ đó thay vì cơ sở dữ liệu, cập nhật biểu đồ khi DB thay đổi.

Nhưng rất lớn, một tải ngây thơ sẽ chiếm ít nhất 6GB bộ nhớ với dữ liệu sẽ tăng lên trong tương lai. (Tôi không có số liệu chính xác, một khi rõ ràng rằng máy 2 GB của tôi đang cố gắng đối phó với ít nhất 6 GB, tôi có tất cả các phép đo tôi cần để biết nó sẽ không hoạt động).

May mắn thay, có một số lượng lớn các đối tượng bất biến trong quần thể dữ liệu này giống nhau; một khi tôi đã tìm ra rằng một lô nhất định giống như một lô khác, tôi có thể bí danh một tham chiếu đến một lô khác cho phép thu thập nhiều dữ liệu và do đó phù hợp với mọi thứ trong chưa đến nửa gig.

Tất cả đều tốt và tốt, nhưng đối với điều này vẫn còn vượt qua hơn 6GB đối tượng trong khoảng nửa phút để đến trạng thái này. Còn lại, GC không đối phó; sự tăng đột biến trong hoạt động so với mô hình thông thường của ứng dụng (ít nặng nề hơn đối với các giao dịch mỗi giây) là quá sắc nét.

Vì vậy, định kỳ gọi GC.Collect()trong quá trình xây dựng này có nghĩa là toàn bộ hoạt động trơn tru. Tất nhiên, tôi không gọi thủ công GC.Collect()phần còn lại của thời gian ứng dụng chạy.

Trường hợp thực tế này là một ví dụ tốt về các hướng dẫn khi chúng ta nên sử dụng GC.Collect():

  1. Sử dụng với một trường hợp tương đối hiếm có rất nhiều đối tượng được cung cấp cho bộ sưu tập (giá trị megabyte đã được cung cấp và việc xây dựng biểu đồ này là trường hợp rất hiếm trong suốt vòng đời của ứng dụng (khoảng một phút mỗi tuần).
  2. Làm điều đó khi mất hiệu suất tương đối chấp nhận được; Điều này chỉ xảy ra khi khởi động ứng dụng. (Một ví dụ điển hình khác của quy tắc này là giữa các cấp độ trong trò chơi hoặc các điểm khác trong trò chơi nơi người chơi sẽ không buồn bã vì một chút tạm dừng).
  3. Hồ sơ để chắc chắn có một sự cải thiện. (Khá dễ dàng; "Nó hoạt động" hầu như luôn luôn đập "nó không hoạt động").

Hầu hết thời gian tôi nghĩ rằng tôi có thể có một trường hợp GC.Collect()đáng gọi, bởi vì điểm 1 và 2 được áp dụng, điểm 3 cho thấy nó làm mọi thứ tồi tệ hơn hoặc ít nhất là làm mọi thứ không tốt hơn (và với rất ít hoặc không cải thiện nghiêng về phía không gọi qua như cách tiếp cận có nhiều khả năng chứng minh tốt hơn trong suốt vòng đời của một ứng dụng).


0

Tôi có một cách sử dụng để xử lý rác có phần không chính thống.

Có một thực tế sai lầm rất đáng tiếc trong thế giới C #, về việc thực hiện xử lý đối tượng bằng cách sử dụng thành ngữ xấu xí, cục mịch, không linh hoạt và dễ bị lỗi được gọi là IDis-dispose . MSDN mô tả nó theo chiều dài và rất nhiều người chửi rủa nó, theo nó một cách tôn giáo, dành hàng giờ đồng hồ để thảo luận chính xác về cách nó nên được thực hiện, v.v.

(Xin lưu ý rằng những gì tôi gọi là xấu xí ở đây không phải là mẫu xử lý đối tượng; cái mà tôi gọi là xấu xí là IDisposable.Dispose( bool disposing )thành ngữ cụ thể .)

Thành ngữ này được phát minh vì được cho là không thể đảm bảo rằng hàm hủy của đối tượng của bạn sẽ luôn được trình thu gom rác gọi để dọn sạch tài nguyên, vì vậy mọi người thực hiện dọn dẹp tài nguyên bên trong IDisposable.Dispose()và trong trường hợp họ quên, họ cũng thử thêm một lần nữa trong phạm vi phá hủy. Bạn biết đấy, chỉ trong trường hợp.

Nhưng sau đó, bạn IDisposable.Dispose()có thể có cả các đối tượng được quản lý và không được quản lý để dọn dẹp, nhưng các đối tượng được quản lý không thể được dọn sạch khi IDisposable.Dispose()được gọi từ bên trong bộ hủy, bởi vì chúng đã được người thu gom rác chăm sóc tại thời điểm đó, vì vậy là nhu cầu này đối với một Dispose()phương thức riêng biệt chấp nhận một bool disposingcờ để biết liệu cả hai đối tượng được quản lý và không được quản lý nên được dọn sạch hay chỉ những đối tượng không được quản lý.

Xin lỗi, nhưng điều này chỉ là điên rồ.

Tôi đi theo tiên đề của Einstein, nói rằng mọi thứ nên đơn giản nhất có thể, nhưng không đơn giản hơn. Rõ ràng, chúng ta không thể bỏ qua việc làm sạch tài nguyên, vì vậy giải pháp đơn giản nhất có thể phải bao gồm ít nhất là như vậy. Giải pháp đơn giản tiếp theo liên quan đến việc luôn luôn xử lý mọi thứ vào thời điểm chính xác mà nó được cho là sẽ được xử lý, mà không làm phức tạp mọi thứ bằng cách dựa vào công cụ phá hủy như một sự thay thế.

Bây giờ, nói một cách nghiêm túc, tất nhiên không thể đảm bảo rằng sẽ không có lập trình viên nào mắc sai lầm khi quên gọi IDisposable.Dispose(), nhưng điều chúng ta có thể làm là sử dụng hàm hủy để bắt lỗi này. Thực sự rất đơn giản: tất cả các hàm hủy phải làm là tạo ra một mục nhật ký nếu nó phát hiện ra rằng disposedcờ của đối tượng dùng một lần không bao giờ được đặt thành true. Vì vậy, việc sử dụng chất hủy không phải là một phần không thể thiếu trong chiến lược xử lý của chúng tôi, nhưng nó là cơ chế đảm bảo chất lượng của chúng tôi. Và vì đây là thử nghiệm chỉ ở chế độ gỡ lỗi, chúng tôi có thể đặt toàn bộ bộ hủy của chúng tôi trong một #if DEBUGkhối, vì vậy chúng tôi không bao giờ phải chịu bất kỳ hình phạt hủy diệt nào trong môi trường sản xuất. (Thành IDisposable.Dispose( bool disposing )ngữ quy định rằngGC.SuppressFinalize() nên được gọi chính xác để giảm chi phí hoàn thiện, nhưng với cơ chế của tôi, có thể tránh hoàn toàn chi phí đó trên môi trường sản xuất.)

Cái mà nó hiểu là lỗi cứng vĩnh cửu so với đối số lỗi mềm : IDisposable.Dispose( bool disposing )thành ngữ là cách tiếp cận lỗi mềm và nó thể hiện nỗ lực cho phép lập trình viên quên gọi Dispose()mà không bị lỗi hệ thống, nếu có thể. Cách tiếp cận lỗi cứng nói rằng lập trình viên phải luôn đảm bảo rằng nó Dispose()sẽ được gọi. Hình phạt thường được quy định bởi phương pháp lỗi cứng trong hầu hết các trường hợp là lỗi xác nhận, nhưng đối với trường hợp cụ thể này, chúng tôi tạo ra một ngoại lệ và giảm hình phạt cho việc ban hành một mục nhật ký lỗi đơn giản.

Vì vậy, để cơ chế này hoạt động, phiên bản DEBUG của ứng dụng của chúng tôi phải thực hiện xử lý rác đầy đủ trước khi thoát, để đảm bảo rằng tất cả các hàm hủy sẽ được gọi, và do đó bắt bất kỳ IDisposableđối tượng nào chúng tôi quên xử lý.


Now, strictly speaking, it is of course impossible to guarantee that no programmer will ever make the mistake of forgetting to invoke IDisposable.Dispose()Trên thực tế, không phải vậy, mặc dù tôi không nghĩ C # có khả năng đó. Đừng để lộ tài nguyên; thay vào đó cung cấp DSL để mô tả mọi thứ bạn sẽ làm với nó (về cơ bản, một đơn nguyên), cộng với chức năng thu nhận tài nguyên, thực hiện mọi việc, giải phóng nó và trả về kết quả. Mẹo nhỏ là sử dụng hệ thống loại để đảm bảo rằng nếu ai đó đưa ra một tham chiếu đến tài nguyên, thì nó không thể được sử dụng trong một cuộc gọi khác đến chức năng chạy.
Doval

2
Vấn đề với Dispose(bool disposing)(không được xác định trên IDisposablelà nó được sử dụng để xử lý dọn dẹp cả các đối tượng được quản lý và không được quản lý mà đối tượng có như một trường (hoặc có trách nhiệm khác), đó là giải quyết vấn đề sai. các đối tượng không được quản lý trong một đối tượng được quản lý không có đối tượng dùng một lần nào khác để lo lắng, sau đó tất cả các Dispose()phương thức sẽ là một trong những đối tượng đó (yêu cầu trình hoàn thiện làm sạch giống nhau nếu cần thiết) hoặc chỉ xử lý các đối tượng được xử lý (không có trình hoàn thiện ở tất cả), và sự cần thiết phải bool disposingbiến mất.
Jon Hanna

-1 lời khuyên tồi vì cách thức hoàn thiện thực sự hoạt động. Tôi hoàn toàn đồng ý với quan điểm của bạn về dispose(disposing)thành ngữ là terribad, nhưng tôi nói như vậy bởi vì mọi người thường sử dụng kỹ thuật và công cụ hoàn thiện đó khi họ chỉ quản lý tài nguyên ( DbConnectionví dụ như đối tượng được quản lý , nó không bị chèn ép hoặc bị thay thế) và BẠN CHỈ NÊN NGAY LẬP TỨC MỘT CUỐI CÙNG VỚI BAN ĐẦU, PINVOKED, COM MARSHALLED, HOẶC MÃ SỐ KHÔNG AN TOÀN . Tôi đã trình bày chi tiết ở trên trong câu trả lời của mình về việc những người hoàn thiện đắt đỏ như thế nào, đừng sử dụng chúng trừ khi bạn có tài nguyên không được quản lý trong lớp.
Jimmy Hoffa

2
Tôi gần như muốn cho bạn +1 mặc dù chỉ vì bạn đang chê bai điều gì đó mà nhiều người coi là điều quan trọng cốt lõi trong dispose(dispoing)thành ngữ, nhưng sự thật là nó chỉ phổ biến vì mọi người rất sợ những thứ không liên quan đến GC rằng ( disposenên có zilch để làm với GC) công đức cho họ chỉ dùng thuốc theo quy định mà không cần điều tra. Tốt cho bạn vì đã kiểm tra nó, nhưng bạn đã bỏ lỡ toàn bộ lớn nhất (nó khuyến khích người hoàn thành farrr thường xuyên hơn họ nên)
Jimmy Hoffa

1
@JimmyHoffa cảm ơn bạn đã đóng góp. Tôi đồng ý rằng bộ hoàn thiện thường chỉ được sử dụng để giải phóng các tài nguyên không được quản lý, nhưng bạn có đồng ý rằng trên bản dựng DEBUG quy tắc này không thể áp dụng được không, và trên bản dựng DEBUG, chúng ta có nên tự do sử dụng bộ hoàn thiện để bắt lỗi không? Đó là tất cả những gì tôi đề nghị ở đây, vì vậy tôi không hiểu tại sao bạn gặp vấn đề với nó. Xem thêm lập trình viên.stackexchange.com / questions / 288715 / Khăn để được giải thích dài hơn về phương pháp này ở phía java của thế giới.
Mike Nakis

0

Bạn có thể cho tôi biết trong trường hợp nào nó thực sự là một ý tưởng tốt hoặc hợp lý để buộc thu gom rác? Tôi không yêu cầu các trường hợp cụ thể của C # mà thay vào đó, tất cả các ngôn ngữ lập trình có trình thu gom rác. Tôi biết rằng bạn không thể ép buộc tất cả các ngôn ngữ, như Java, nhưng giả sử bạn có thể.

Chỉ cần nói rất lý thuyết và coi nhẹ các vấn đề như một số triển khai GC làm chậm mọi thứ trong chu kỳ thu thập của chúng, kịch bản lớn nhất tôi có thể nghĩ đến để buộc thu gom rác là một phần mềm quan trọng trong đó rò rỉ logic thích hợp hơn để treo tai nạn con trỏ, ví dụ như, vì sự cố vào những thời điểm không ngờ có thể phải trả giá bằng mạng sống của con người hoặc một cái gì đó thuộc loại này.

Nếu bạn nhìn vào một số trò chơi độc lập shoddier được viết bằng ngôn ngữ GC như trò chơi Flash, chúng sẽ rò rỉ như điên nhưng chúng không gặp sự cố. Họ có thể mất mười lần bộ nhớ trong 20 phút để chơi trò chơi vì một phần của cơ sở mã của trò chơi đã quên đặt tham chiếu thành null hoặc xóa nó khỏi danh sách và tốc độ khung hình có thể bắt đầu bị ảnh hưởng, nhưng trò chơi vẫn hoạt động. Một trò chơi tương tự được viết bằng mã hóa C hoặc C ++ kém chất lượng có thể bị sập do truy cập các con trỏ lơ lửng do cùng một loại lỗi quản lý tài nguyên, nhưng nó sẽ không bị rò rỉ nhiều.

Đối với các trò chơi, sự cố có thể được ưu tiên theo nghĩa là nó có thể được phát hiện và sửa chữa nhanh chóng, nhưng đối với một chương trình quan trọng, việc đâm vào những thời điểm hoàn toàn bất ngờ có thể giết chết ai đó. Vì vậy, các trường hợp chính tôi nghĩ sẽ là các tình huống không bị sập hoặc một số hình thức khác là bảo mật là hoàn toàn quan trọng và rò rỉ logic là một điều tương đối tầm thường khi so sánh.

Kịch bản chính mà tôi nghĩ thật tồi tệ khi buộc GC là cho những điều mà rò rỉ logic thực sự ít được ưa thích hơn là một sự cố. Ví dụ, với các trò chơi, sự cố sẽ không nhất thiết giết chết bất kỳ ai và có thể dễ dàng bắt gặp và khắc phục trong quá trình thử nghiệm nội bộ, trong khi rò rỉ logic có thể không được chú ý ngay cả sau khi sản phẩm xuất xưởng trừ khi nó khiến trò chơi không thể chơi được trong vài phút . Trong một số lĩnh vực, một sự cố dễ tái tạo xảy ra trong thử nghiệm đôi khi tốt hơn là rò rỉ mà không ai nhận thấy ngay lập tức.

Một trường hợp khác tôi có thể nghĩ về nơi có thể tốt hơn để buộc GC vào một nhóm là cho một chương trình rất ngắn, giống như một cái gì đó được thực thi từ dòng lệnh thực hiện một nhiệm vụ và sau đó tắt. Trong trường hợp đó, thời gian tồn tại của chương trình quá ngắn để làm cho bất kỳ loại rò rỉ logic nào trở nên không tầm thường. Rò rỉ logic, ngay cả đối với các tài nguyên lớn, thường chỉ trở thành vấn đề hàng giờ hoặc vài phút sau khi chạy phần mềm, do đó, một phần mềm chỉ được thực hiện trong 3 giây dường như không bao giờ gặp sự cố với rò rỉ logic và nó có thể khiến mọi thứ rất nhiều đơn giản hơn để viết các chương trình ngắn như vậy nếu nhóm chỉ sử dụng GC.

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.