2012-05-18 46 views
6

Tôi đã thử nghiệm với thiết kế ngôn ngữ lập trình và đã đến mức cần triển khai hệ thống thu gom rác. Bây giờ điều đầu tiên xuất hiện trong đầu bạn là đếm tham chiếu, nhưng điều này sẽ không xử lý các vòng tham chiếu. Hầu hết các trang mà tôi gặp phải khi tìm kiếm các thuật toán là các tham chiếu về điều chỉnh các bộ thu gom rác trong các ngôn ngữ hiện có, chẳng hạn như Java. Khi tôi tìm thấy bất cứ điều gì mô tả thuật toán cụ thể, tôi không nhận được đủ chi tiết để triển khai. Ví dụ: hầu hết các mô tả bao gồm "khi chương trình của bạn sắp hết bộ nhớ ...", điều này không có khả năng xảy ra bất kỳ lúc nào sớm trên hệ thống 4 GB với nhiều trao đổi. Vì vậy, những gì tôi đang tìm kiếm là một số hướng dẫn với các chi tiết thực hiện tốt như cách điều chỉnh thời điểm khởi động bộ thu gom rác (tức là thu thập sau số lần cấp phát bộ nhớ X hoặc mỗi phút Y, v.v.).Thuật toán thu gom rác đơn giản để thử nghiệm với một thông dịch viên đơn giản là gì?

Để cung cấp thêm một vài chi tiết về những gì tôi đang cố gắng, tôi bắt đầu bằng cách viết một trình thông dịch dựa trên stack tương tự như Postscript, và nỗ lực tiếp theo của tôi có thể là ngôn ngữ biểu thức S dựa trên của các phương ngữ Lisp. Tôi đang thực hiện thẳng C. Mục tiêu của tôi là cả tự học, và ghi lại các giai đoạn khác nhau thành một hướng dẫn "cách thiết kế và viết một thông dịch viên".

Đối với những gì tôi đã làm cho đến nay, tôi đã viết một trình thông dịch đơn giản, thực hiện ngôn ngữ mệnh lệnh kiểu C, được phân tích và xử lý bởi máy ảo kiểu máy xếp chồng (xem lang2e.sourceforge.net). Nhưng ngôn ngữ này không cấp phát bộ nhớ mới khi nhập bất kỳ hàm nào, và không có bất kỳ kiểu dữ liệu con trỏ nào, do đó không cần thiết cho bất kỳ kiểu quản lý bộ nhớ nâng cao nào. Đối với dự án tiếp theo của tôi, tôi đang nghĩ đến việc bắt đầu với việc đếm tham chiếu cho các đối tượng kiểu không phải con trỏ (số nguyên, chuỗi, vv), và sau đó theo dõi bất kỳ đối tượng kiểu con trỏ nào (có thể tạo tham chiếu vòng tròn) trong một nhóm bộ nhớ riêng biệt . Sau đó, bất cứ khi nào hồ bơi phát triển hơn X đơn vị phân bổ nhiều hơn vào cuối chu kỳ thu gom rác trước đó, hãy khởi động lại bộ thu thập.

Yêu cầu của tôi là nó không quá kém hiệu quả, dễ thực hiện và tài liệu rõ ràng (hãy nhớ, tôi muốn phát triển điều này thành một bài báo hoặc sách để người khác theo dõi). Thuật toán mà tôi hiện đang có ở mặt trước là đánh dấu ba màu, nhưng có vẻ như một nhà sưu tập thế hệ sẽ tốt hơn một chút, nhưng khó hơn trong việc ghi chép và hiểu. Vì vậy, tôi đang tìm một số tài liệu tham khảo rõ ràng (tốt nhất là có sẵn trực tuyến) bao gồm đủ chi tiết triển khai để giúp tôi bắt đầu.

+1

Google 'Mark and Sweep' –

+0

Tôi nên thêm rằng tôi đã thấy mô tả của một số nhà sưu tập rác, chẳng hạn như các biến thể về đánh dấu và quét, nhưng hầu hết các trang tôi đã chạy không tốt hơn nhiều so với Bài viết trên Wikipedia. Ví dụ, như tôi đã đề cập trong câu hỏi, họ nói để đá nó khi bộ nhớ bị thấp. Điều đó không có khả năng xảy ra trên các hệ thống hiện đại trong suốt thời gian chạy của hầu hết các kịch bản nhẹ, và thậm chí nếu nó có, nó sẽ không tốt để sử dụng hết bộ nhớ hệ thống trước khi khởi động bộ thu. Chi tiết như vậy là những gì tôi đang tìm kiếm. –

+0

http://doc.cat-v.org/inferno/concurrent_gc/ - phải là quá đủ chi tiết để triển khai. –

Trả lời

4

Có một cuốn sách tuyệt vời về bộ sưu tập rác. Nó được gọi là Bộ sưu tập rác: Các thuật toán cho quản lý bộ nhớ động tự động và rất tuyệt vời. Tôi đã đọc nó, vì vậy tôi không đề xuất điều này chỉ vì bạn có thể tìm thấy nó với Google. Nhìn vào nó here.

Để tạo mẫu đơn giản, hãy sử dụng tính năng đánh dấu và quét hoặc bất kỳ trình thu gọn nén không thế hệ, không gia tăng đơn giản nào. Người thu gom gia tăng chỉ tốt nếu bạn cần cung cấp phản hồi "thời gian thực" từ hệ thống của bạn. Miễn là hệ thống của bạn được phép trễ tùy ý tại bất kỳ thời điểm cụ thể nào, bạn không cần một hệ thống tăng dần. Các nhà sưu tầm thế hệ giảm chi phí thu gom rác trung bình với chi phí giả định một cái gì đó về vòng đời của vật thể.

Tôi đã triển khai tất cả bộ thu gom rác (thế hệ/không thế hệ, gia tăng/không gia tăng) và gỡ lỗi là khá khó. Bởi vì bạn muốn tập trung vào thiết kế ngôn ngữ của mình, và có thể không quá nhiều khi gỡ lỗi một bộ thu gom rác phức tạp hơn, bạn có thể dính vào một thiết bị đơn giản. Tôi sẽ đánh dấu và quét rất nhiều khả năng.

Khi bạn sử dụng bộ sưu tập rác, bạn không cần tính tham chiếu. Ném nó đi.

+0

Về việc ném ra tính tham chiếu, sẽ có một số đối tượng có độ thoáng qua cao, chủ yếu là các đối tượng tạm thời trên ngăn xếp - ví dụ "2 * 3 + 5" (hoặc theo thứ tự RPN, "2 3 * 5 + "sẽ để lại" 6 "trên stack cho đến khi các nhà điều hành thêm tiêu thụ nó.Chỉ cần đánh dấu và quét, có vẻ như GC sẽ được khởi động khá thường xuyên. Tuy nhiên, điều này vẫn còn hiệu quả hơn so với chi phí đếm ref? Hay là Có một tối ưu hóa khác tôi nên xem xét đối với các đối tượng tạm thời này? Cảm ơn –

+0

Bộ sưu tập rác nhanh hơn so với tính tham khảo nếu bạn có thể thực hiện GC ít khi thực sự. Tham khảo đếm cũng tiêu thụ bộ nhớ thêm bởi vì bạn cần phải lưu trữ các lĩnh vực đếm tham khảo chính nó.Lưu ý rằng bình thường tuy nhiên bạn sẽ không phân bổ số nguyên ở tất cả, nhưng sẽ r epresent chúng tại chỗ, thay cho con trỏ đến các đối tượng GC'd. –

+0

Ok, vì vậy tôi sẽ giải quyết bằng cách sử dụng một trong hai đánh dấu và quét, hoặc dừng & sao chép, và có thể mở rộng nó đến một nhà sưu tập thế hệ đơn giản. Tôi có thể thấy cách một nhà sưu tập hai thế hệ có thể giúp đỡ với các đối tượng thoáng qua, đặc biệt là với việc dừng & sao chép. Bây giờ, vì tôi có kế hoạch ghi lại mọi giai đoạn tiến bộ của mình để tạo thành một hướng dẫn, bạn có nghĩ rằng tôi nên bắt đầu với việc đếm tham chiếu và chứng minh sự thiếu sót của nó, sau đó phát triển nó thành một thứ gì đó tốt hơn trong quá trình viết? Tôi giả định rằng tôi có thể có cùng một giao diện chung được tiếp xúc với phần còn lại của trình thông dịch và cắm vào các GC khác nhau nếu cần. –

1

Khi khởi động bộ cấp phát có thể mở rộng - bạn có thể GC khi cấp phát bộ nhớ bị lỗi hoặc bạn có thể GC mỗi lần tham chiếu bị bỏ hoặc bất kỳ vị trí nào ở giữa.

Chờ cho đến khi bạn không có lựa chọn nào có nghĩa là bạn không bao giờ GC, nếu mã đang chạy được chứa khá tốt. Hoặc, nó có thể giới thiệu một sự tạm dừng khổng lồ vào môi trường của bạn và phá hủy thời gian phản hồi hoặc hoạt ảnh hoặc phát lại âm thanh hoàn toàn.

Chạy toàn bộ GC trên mỗi free() có thể phân bổ chi phí trên nhiều hoạt động hơn, mặc dù toàn bộ hệ thống có thể chạy chậm hơn do đó. Bạn có thể dự đoán được nhiều hơn, nhưng chậm hơn tổng thể.

Nếu bạn muốn thử nghiệm điều này bằng bộ nhớ giới hạn giả tạo, bạn có thể chỉ cần chạy với giới hạn tài nguyên rất hạn chế tại chỗ. Chạy ulimit -v 1024 và mọi quá trình sinh ra bởi trình bao đó sẽ chỉ có một megabyte bộ nhớ để hoạt động.

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