Xoay câu hỏi của bạn xung quanh. Câu hỏi thúc đẩy thực sự là trong những trường hợp nào chúng ta có thể tránh được các chi phí thu gom rác?
Vâng, trước hết, những gì là chi phí cho việc thu gom rác thải? Có hai chi phí chính. Đầu tiên, bạn phải xác định cái gì còn sống ; điều đó đòi hỏi tiềm năng rất nhiều công việc Thứ hai, bạn phải thu gọn các lỗ hổng được hình thành khi bạn giải phóng thứ gì đó được phân bổ giữa hai thứ vẫn còn sống. Những cái lỗ đó thật lãng phí. Nhưng nén chúng cũng đắt tiền.
Làm thế nào chúng ta có thể tránh những chi phí này?
Rõ ràng nếu bạn có thể tìm thấy một mô hình sử dụng lưu trữ mà bạn không bao giờ phân bổ một cái gì đó tồn tại lâu dài, sau đó phân bổ một cái gì đó tồn tại trong thời gian ngắn, sau đó phân bổ một cái gì đó tồn tại lâu dài, bạn có thể loại bỏ chi phí lỗ hổng. Nếu bạn có thể đảm bảo rằng đối với một số tập hợp con của bộ lưu trữ của bạn, mọi phân bổ tiếp theo sẽ có thời gian sử dụng ngắn hơn bộ lưu trữ trước đó, thì sẽ không bao giờ có bất kỳ lỗ hổng nào trong bộ lưu trữ đó.
Nhưng nếu chúng ta giải quyết được vấn đề lỗ thì chúng ta cũng đã giải quyết vấn đề thu gom rác . Bạn có một cái gì đó trong kho lưu trữ vẫn còn sống? Vâng. Là tất cả mọi thứ được phân bổ trước khi nó sống lâu hơn? Vâng - giả định đó là cách chúng tôi loại bỏ khả năng lỗ hổng. Do đó, tất cả những gì bạn cần làm là nói "phân bổ gần đây nhất còn sống?" và bạn biết rằng mọi thứ đều sống trong kho lưu trữ đó.
Chúng ta có một bộ phân bổ lưu trữ mà chúng ta biết rằng mọi phân bổ tiếp theo có thời gian tồn tại ngắn hơn phân bổ trước đó không? Vâng! Các khung kích hoạt của các phương thức luôn bị phá hủy theo thứ tự ngược lại mà chúng được tạo bởi vì chúng luôn có thời gian tồn tại ngắn hơn kích hoạt đã tạo ra chúng.
Do đó, chúng ta có thể lưu trữ các khung kích hoạt trên ngăn xếp và biết rằng chúng không bao giờ cần phải được thu thập. Nếu có bất kỳ khung nào trên ngăn xếp, toàn bộ bộ khung bên dưới nó sẽ tồn tại lâu hơn, vì vậy chúng không cần phải được thu thập. Và chúng sẽ bị phá hủy theo thứ tự ngược lại mà chúng được tạo ra. Do đó, chi phí cho việc thu gom rác được loại bỏ cho các khung kích hoạt.
Đó là lý do tại sao chúng ta có nhóm tạm thời trên ngăn xếp ở vị trí đầu tiên: bởi vì đây là cách dễ dàng để thực hiện kích hoạt phương thức mà không bị phạt quản lý bộ nhớ.
(Tất nhiên là chi phí thu gom rác bộ nhớ được tham chiếu bởi các tham chiếu trên các khung kích hoạt vẫn còn đó.)
Bây giờ hãy xem xét một hệ thống luồng điều khiển trong đó các khung kích hoạt không bị phá hủy theo thứ tự dự đoán. Điều gì xảy ra nếu kích hoạt trong thời gian ngắn có thể làm phát sinh kích hoạt lâu dài? Như bạn có thể tưởng tượng, trong thế giới này, bạn không còn có thể sử dụng ngăn xếp để tối ưu hóa nhu cầu thu thập kích hoạt. Tập hợp kích hoạt có thể chứa lỗ một lần nữa.
C # 2.0 có tính năng này ở dạng yield return
. Một phương thức thực hiện trả lại lợi tức sẽ được kích hoạt lại vào lần sau - lần tiếp theo mà MoveNext được gọi - và khi điều đó xảy ra là không thể dự đoán được. Do đó, thông tin thường có trên ngăn xếp cho khung kích hoạt của khối lặp thay vào đó được lưu trữ trên heap, nơi nó được thu gom rác khi thu thập dữ liệu.
Tương tự, tính năng "async / await" có trong các phiên bản tiếp theo của C # và VB sẽ cho phép bạn tạo các phương thức có kích hoạt "nhường" và "tiếp tục" tại các điểm được xác định rõ trong quá trình hoạt động của phương thức. Vì các khung kích hoạt không còn được tạo và hủy theo cách có thể dự đoán được, tất cả thông tin đã từng được lưu trữ trong ngăn xếp sẽ phải được lưu trữ trong heap.
Đó chỉ là một tai nạn của lịch sử mà chúng tôi đã quyết định trong một vài thập kỷ rằng các ngôn ngữ có khung kích hoạt được tạo ra và phá hủy theo một trật tự nghiêm ngặt là thời thượng. Vì các ngôn ngữ hiện đại ngày càng thiếu tài sản này, hy vọng sẽ thấy ngày càng nhiều ngôn ngữ thống nhất các phần tiếp theo vào đống rác được thu gom, thay vì ngăn xếp.