2016-05-21 19 views
5

Tôi đang viết một trình thông dịch lisp đơn giản từ đầu. Tôi có một môi trường toàn cầu mà các biến cấp cao nhất bị ràng buộc trong khi đánh giá tất cả các biểu mẫu trong một tệp. Khi tất cả các biểu mẫu trong tệp đã được đánh giá, mức env cao nhất và tất cả các cấu trúc dữ liệu giá trị khóa bên trong của nó được giải phóng.khi để giải phóng bộ nhớ của một đóng cửa trong một thông dịch viên lisp

Khi bộ đánh giá gặp mẫu lambda, nó tạo đối tượng PROC chứa 3 điều: danh sách đối số được gắn trong khung cục bộ khi áp dụng quy trình, phần thân của hàm và con trỏ đến môi trường nó đã được tạo ra trong Ví dụ:.

(lambda (x) x) 

sẽ tạo ra một cái gì đó trong nội bộ như:

PROC- args: x, 
     body: x, 
     env: pointer to top level env 

Khi PROC được áp dụng, một môi trường mới được tạo cho khung và thứ e bindings địa phương được tổ chức ở đó để cho phép cơ thể được đánh giá với các ràng buộc thích hợp. Môi trường khung này chứa một con trỏ để đóng của nó để cho phép tra cứu biến bên trong R THNG. Trong trường hợp này, đó sẽ là môi trường toàn cầu. Sau khi cơ thể PROC được đánh giá, tôi có thể giải phóng tất cả các ô được liên kết với nó bao gồm môi trường khung của nó và thoát ra mà không bị rò rỉ bộ nhớ.

Vấn đề của tôi là có chức năng đặt hàng cao hơn. Hãy xem xét điều này:

(define conser 
    (lambda (x) 
     (lambda (y) (cons x y)))) 

Một hàm lấy một đối số và tạo ra một hàm khác sẽ phản đối đối số của bạn đối với thứ bạn truyền vào nó. Vì vậy,

(define aconser (conser '(1))) 

Sẽ mang lại một chức năng theo ý muốn '(1) cho bất kỳ nội dung nào được chuyển vào đó. ví dụ:

(aconser '(2)) ; ((1) 2) 

Vấn đề của tôi ở đây là aconser phải giữ lại một con trỏ đến môi trường nó được thành lập năm, cụ thể là của conser khi là được sản xuất thông qua gọi (conser '(1)). Khi áp dụng aconser, PROC được áp dụng, khung của nó phải trỏ đến khung conser đã tồn tại khi aconser được xác định, vì vậy tôi không thể giải phóng khung conser sau khi áp dụng. Tôi không biết làm thế nào/cách tốt nhất để giải phóng bộ nhớ liên quan đến khung lambda khi nó được áp dụng và cũng hỗ trợ loại hàm bậc cao liên tục này.

tôi có thể nghĩ ra một số giải pháp:

  • một số loại ARC

  • sao chép các môi trường kèm theo vào khung của PROC đánh giá khi nó được sản xuất

này dường như là những gì đang được ngụ ý here. Vì vậy, thay vì lưu một con trỏ trong đối tượng PROC để đóng cửa, tôi sẽ ... sao chép môi trường đóng và lưu con trỏ đến rằng trực tiếp trong ô?? Điều này sẽ không chỉ là đá một người có thể cấp sâu hơn và kết quả trong cùng một vấn đề?

  • đệ quy thay thế các nhãn lúc đọc bên trong cơ thể của hàm bậc cao

tôi lo lắng tôi có thể thiếu một cái gì đó rất đơn giản ở đây, và tôi cũng tò mò như thế nào thủ tục này được hỗ trợ trong các triển khai khác của lisp và các ngôn ngữ khác có đóng cửa nói chung. Tôi đã không có nhiều may mắn tìm kiếm câu trả lời vì câu hỏi rất cụ thể, có lẽ ngay cả khi thực hiện điều này (rằng tôi thừa nhận rằng chỉ cần kéo mũ của mình như một dự án học tập) và phần lớn những gì tôi có thể tìm thấy của các đóng cửa từ ngôn ngữ đang được thực hiện, không phải từ ngôn ngữ mà ngôn ngữ đang được thực hiện trong.

Here is a link vào dòng có liên quan trong nguồn của tôi, nếu nó hữu ích và tôi rất sẵn lòng giải thích nếu câu hỏi này không đủ chi tiết để mô tả sự cố một cách kỹ lưỡng. Cảm ơn!

+1

Tôi có thể thiếu thứ gì đó, nhưng bạn nói "sau khi cơ quan PROC được đánh giá, tôi có thể giải phóng tất cả các ô liên kết với nó bao gồm môi trường khung và thoát ra mà không bị rò rỉ bộ nhớ." Bạn không thể tái sử dụng việc đóng cửa nhiều lần? trong trường hợp này bạn sẽ giải phóng môi trường quá sớm. – coredump

+0

Đó chính là vấn đề.Tôi đang vẽ một sự khác biệt ở đây giữa đóng cửa (bất cứ điều gì env một lambda xảy ra được đánh giá trong, kết quả là một proc) và khung, đó là các ràng buộc địa phương của các biến nội bộ để một proc khi nó được áp dụng. Tôi có thể hiểu lầm những thuật ngữ này trong lịch sử mặc dù ... – jfo

+0

vì vậy nếu tôi có một lambda chỉ là một cấp độ sâu, khung của nó được tái tạo mỗi khi nó được áp dụng, sử dụng bất cứ điều gì args đã được chuyển cho nó. – jfo

Trả lời

1

Cách xử lý này thường được sử dụng trong phiên dịch ngây thơ là sử dụng bộ thu gom rác (GC) và phân bổ khung kích hoạt của bạn trong vùng heap GC'd. Vì vậy, bạn không bao giờ rõ ràng miễn phí những khung hình đó, bạn cho phép GC giải phóng chúng khi áp dụng.

Trong triển khai phức tạp hơn, bạn có thể sử dụng một cách tiếp cận hơi khác nhau:

  • khi đóng cửa được tạo ra, không lưu trữ một con trỏ đến môi trường hiện tại. Thay vào đó, hãy sao chép giá trị của các biến đó được sử dụng bởi việc đóng (được gọi là các biến miễn phí của lambda). và thay đổi phần thân của bản đóng để sử dụng các bản sao đó thay vì xem xét môi trường cho các biến đó. Nó được gọi là chuyển đổi đóng cửa.
  • Giờ đây, bạn có thể xử lý môi trường của mình dưới dạng ngăn xếp thông thường và khung kích hoạt miễn phí ngay khi bạn thoát khỏi phạm vi.
  • Bạn vẫn cần GC để quyết định khi nào đóng cửa có thể được giải phóng.
  • điều này lần lượt yêu cầu "chuyển đổi chuyển nhượng": sao chép giá trị của các biến ngụ ý thay đổi ngữ nghĩa nếu các biến đó được sửa đổi. Vì vậy, để khôi phục ngữ nghĩa ban đầu, bạn cần phải tìm các biến đó được "sao chép vào một đóng" cũng như "đã sửa đổi" và biến chúng thành "ô tham chiếu" (ví dụ: ô cons nơi bạn giữ giá trị car), sao cho bản sao không sao chép giá trị nữa, nhưng chỉ sao chép một tham chiếu đến vị trí thực tế mà giá trị được giữ. [Lưu ý phụ: việc triển khai như vậy rõ ràng ngụ ý rằng tránh setq và sử dụng phong cách chức năng hơn có thể sẽ trở nên hiệu quả hơn. ]

Việc thực hiện phức tạp hơn cũng có lợi thế mà nó có thể cung cấp một an toàn cho không gian ngữ nghĩa: a đóng cửa sẽ chỉ giữ cho dữ liệu mà nó thực sự đề cập, trái với cách tiếp cận ngây thơ nơi đóng cửa kết thúc đề cập đến toàn bộ môi trường xung quanh và do đó có thể ngăn GC thu thập dữ liệu không thực sự được tham chiếu nhưng chỉ xảy ra trong môi trường tại thời điểm nó bị đóng bởi việc đóng cửa.

+0

ty, đây là một câu trả lời kỹ lưỡng và về cơ bản phản ánh những gì nghiên cứu hậu hỏi của tôi đã cho tôi thấy. Đối với đồ chơi của tôi, tôi quyết định rằng GC nằm ngoài phạm vi dự án ban đầu của tôi và vì vậy tôi đã không thực hiện nó, nhưng tôi dự định thử tiếp theo của tôi :) – jfo

+0

Bạn có thể đọc về những gì tôi đã kết thúc với [ở đây] (http://blog.jfo.click/sild-is-a-lisp-dialect/). – jfo

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