An toàn bộ nhớ dựa trên loại mà không có quản lý bộ nhớ thủ công hoặc bộ sưu tập rác thời gian chạy?


12

Giả sử chúng ta muốn có một ngôn ngữ lập trình chức năng thuần túy, như Haskell hoặc Idris, nhằm mục đích lập trình hệ thống mà không cần thu gom rác và không có thời gian chạy (hoặc ít nhất là không nhiều hơn "thời gian chạy" của C và Rust). Một cái gì đó có thể chạy, ít nhiều, trên kim loại trần.

Một số tùy chọn cho an toàn bộ nhớ tĩnh không yêu cầu quản lý bộ nhớ thủ công hoặc thu gom rác thời gian chạy và vấn đề có thể được giải quyết bằng cách sử dụng hệ thống loại của một chức năng thuần túy tương tự như Haskell hoặc Idris?


Bạn đang nói rằng bạn thích các loại trong ngôn ngữ để phục vụ như là một cách để tránh thu gom rác? Vấn đề cơ bản phát sinh trong việc đánh giá các chức năng. Một hàm được ước tính cho một bao đóng, đóng gói môi trường thời gian chạy hiện tại. Đó là nguồn chính của việc phải thu gom rác. Trừ khi bạn thay đổi quy tắc gõ cho các hàm, tôi sẽ không thấy các kiểu sẽ giúp với điều này như thế nào. Java và các ngôn ngữ khác với chia -abstractions get aroudn này bằng cách mutliating sự hình thành của đóng cửa: họ không cho phép tài liệu tham khảo mà sẽ yêu cầu thu gabrage. λ
Andrej Bauer

Chắc chắn Rust phải giải quyết vấn đề tương tự về đánh giá và đóng cửa chức năng với mô hình sở hữu và công cụ kiểm tra vay? Quản lý bộ nhớ chỉ có nghĩa là biết các giá trị còn tồn tại bao lâu, các giá trị khác phụ thuộc vào chúng và phá hủy các giá trị không sử dụng khi chúng chết, phải không? Vì vậy, tôi đoán tôi thực sự hỏi liệu quản lý bộ nhớ có thể được gói gọn trong một tập hợp các loại có thể được kiểm tra tính chính xác thông qua hệ thống loại hay không, mà không mở rộng bộ máy cơ bản của ngôn ngữ hoặc trình biên dịch bằng cách thêm một hệ thống sở hữu hoàn toàn mới và "mượn người kiểm tra "(đó là cách của Rust).
Đuổi theo ngày

Điều gì về LFPL của Martin Hofmann ? Nó có một loại cơ sở đặc biệt, "kim cương", trong đó một quy tắc loại tuyến tính được thi hành, cho phép các loại tính toán cho việc sử dụng bộ nhớ cơ bản (cấp phát / phân bổ). Điều đó sẽ đi theo hướng bạn đang nói về?
Damiano Mazza

Câu trả lời:


18

Nói một cách đơn giản, có hai chiến lược chính để quản lý bộ nhớ thủ công an toàn.

  1. Cách tiếp cận đầu tiên là sử dụng một số logic cấu trúc con như logic tuyến tính để kiểm soát việc sử dụng tài nguyên. Ý tưởng này đã xuất hiện xung quanh về cơ bản kể từ khi bắt đầu logic tuyến tính, và về cơ bản hoạt động trên quan sát rằng bằng cách cấm quy tắc cấu trúc của sự co lại, mọi biến được sử dụng nhiều nhất một lần, và do đó không có bí danh. Do đó, sự khác biệt giữa cập nhật tại chỗ và phân bổ lại là vô hình đối với chương trình và do đó bạn có thể thực hiện ngôn ngữ của mình bằng quản lý bộ nhớ thủ công.

    Đây là những gì Rust làm (nó sử dụng một hệ thống kiểu affine). Nếu bạn quan tâm đến lý thuyết về ngôn ngữ theo phong cách Rust, một trong những bài viết hay nhất là L3: A Ngôn ngữ tuyến tính với các địa điểm của Ahmed et al . Bên cạnh đó, tính toán của LFPL mà Damiano Mazza đã đề cập cũng là tuyến tính, có một ngôn ngữ đầy đủ bắt nguồn từ ngôn ngữ RAML .

    Nếu bạn quan tâm đến xác minh theo kiểu Idris, bạn nên xem ngôn ngữ ATS của Xi et al , là ngôn ngữ kiểu Rust / L3 có hỗ trợ xác minh dựa trên các loại được lập chỉ mục theo kiểu Haskell, chỉ tạo ra bằng chứng không liên quan và tuyến tính để cung cấp thêm kiểm soát hiệu suất.

    Một cách tiếp cận phụ thuộc mạnh mẽ hơn nữa là ngôn ngữ F-star được phát triển tại Microsoft Research, đây là một lý thuyết loại phụ thuộc hoàn toàn. Ngôn ngữ này có giao diện đơn âm với các điều kiện trước và sau theo tinh thần của Lý thuyết loại Hoare của Nanevski và cộng sự (hoặc thậm chí cả các loại tuyến tính và phụ thuộc tích hợp của riêng tôi ) và có một tập hợp con được xác định có thể được biên dịch thành mã C cấp thấp - trên thực tế, họ đang vận chuyển mã tiền điện tử đã được xác minh như một phần của Firefox rồi!

    Rõ ràng, cả F-star và HTT đều không phải là ngôn ngữ được gõ tuyến tính, nhưng ngôn ngữ chỉ mục cho các đơn vị của chúng thường dựa trên logic phân tách của Reynold và O'Hearn , là logic cấu trúc liên quan đến logic tuyến tính đã thấy thành công lớn như ngôn ngữ khẳng định cho logic Hoare cho các chương trình con trỏ.

  2. Cách tiếp cận thứ hai chỉ đơn giản là chỉ định lắp ráp (hoặc bất kỳ IR cấp thấp nào bạn muốn), sau đó sử dụng một số dạng logic tuyến tính hoặc phân tách để lý giải trực tiếp về hành vi của nó trong trợ lý chứng minh. Về cơ bản, bạn có thể sử dụng trợ lý bằng chứng hoặc ngôn ngữ được gõ phụ thuộc như một trình biên dịch macro rất lạ mắt chỉ tạo ra các chương trình chính xác.

    Logic phân tách mức cao của Jensen và cộng sự cho mã cấp thấp là một ví dụ đặc biệt thuần túy về điều này - nó xây dựng logic phân tách cho lắp ráp x86! Tuy nhiên, có rất nhiều dự án trong tĩnh mạch này, như Công cụ phần mềm được xác minh tại Princeton và dự án CertiKOS tại Yale.

Tất cả các cách tiếp cận này sẽ "cảm thấy" giống như Rust, vì theo dõi quyền sở hữu bằng cách hạn chế việc sử dụng các biến là chìa khóa cho tất cả chúng.


3

Các loại tuyến tính và logic phân tách đều tuyệt vời, nhưng có thể đòi hỏi khá nhiều nỗ lực của lập trình viên. Chẳng hạn, viết một danh sách liên kết an toàn trong Rust có thể khá khó khăn.

Nhưng có một sự thay thế đòi hỏi nỗ lực lập trình ít hơn nhiều, mặc dù với sự đảm bảo ít nghiêm ngặt hơn. Luồng công việc (khá cũ) là đảm bảo an toàn cho bộ nhớ bằng cách sử dụng (thường là một chồng) các vùng. Sử dụng suy luận khu vực, một trình biên dịch có thể quyết định tĩnh khu vực mà một phần dữ liệu được phân bổ sẽ đi vào và phân bổ khu vực khi nó đi ra khỏi phạm vi.

Suy luận khu vực có thể an toàn (không thể giải phóng bộ nhớ có thể tiếp cận) và yêu cầu sự can thiệp của lập trình viên tối thiểu, nhưng nó không phải là "tổng" (nghĩa là nó vẫn có thể rò rỉ bộ nhớ, mặc dù chắc chắn tốt hơn nhiều so với "không làm gì"), vì vậy nó thường được kết hợp với GC trong thực tế. CácMLtonTrình biên dịch ML Kit sử dụng các vùng để loại bỏ hầu hết các cuộc gọi GC, nhưng nó vẫn có một GC vì nó vẫn sẽ rò rỉ bộ nhớ. Theo một số người tiên phong đầu tiên về các khu vực, suy luận khu vực không thực sự được phát minh cho mục đích này (tôi nghĩ đó là để song song hóa tự động); nhưng hóa ra nó cũng có thể được sử dụng để quản lý bộ nhớ.

Để bắt đầu, tôi sẽ nói rằng hãy viết bài "Thực hiện phép tính Call theo giá trị được gõ bằng cách sử dụng một vùng các vùng" của Mads Tofte và Jean-Pierre Talpin. Để biết thêm các bài viết về suy luận khu vực, hãy tìm các bài viết khác của M. Tofte và J.-P. Talpin, một số tác phẩm của Pierre Jouvelot, cũng như loạt bài viết về Cyclone của Greg Morrisett, Mike Hicks và Dan Grossman.


-2

Một sơ đồ tầm thường cho các hệ thống "kim loại trần" chỉ đơn giản là không cho phép tất cả các phân bổ bộ nhớ thời gian chạy. Hãy nhớ rằng, ngay cả malloc/freecặp C yêu cầu một thư viện thời gian chạy. Nhưng ngay cả khi tất cả các đối tượng được xác định tại thời điểm biên dịch, chúng có thể được định nghĩa theo cách an toàn kiểu.

Vấn đề chính ở đây là sự hư cấu về các giá trị bất biến trong các ngôn ngữ chức năng thuần túy, được tạo ra trong khi chương trình chạy. Phần cứng thực sự (và chắc chắn là các hệ thống kim loại trần) dựa vào RAM có thể thay đổi, nguồn cung hạn chế. Thời gian chạy của việc triển khai ngôn ngữ chức năng trong thực tế sẽ phân bổ RAM một cách linh hoạt khi các giá trị "bất biến" mới được tạo ra và rác thu thập chúng khi không còn cần giá trị "bất biến".

Và đối với hầu hết các vấn đề thú vị, tuổi thọ của ít nhất một số giá trị phụ thuộc vào đầu vào thời gian chạy (người dùng), vì vậy thời gian sống không thể được xác định tĩnh. Nhưng ngay cả khi thời gian tồn tại không phụ thuộc vào đầu vào, nó có thể rất không tầm thường. Thực hiện chương trình đơn giản liên tục tìm các số nguyên tố đơn giản bằng cách kiểm tra từng số theo thứ tự, kiểm tra tất cả các số nguyên tố lên đến sqrt(N). Rõ ràng nhu cầu này giữ các số nguyên tố và có thể tái chế bộ nhớ được sử dụng cho các số nguyên tố không.

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.