Tại sao trình biên dịch không tự động chèn thỏa thuận?


63

Trong các ngôn ngữ như C, lập trình viên dự kiến ​​sẽ chèn các cuộc gọi miễn phí. Tại sao trình biên dịch không làm điều này tự động? Con người làm điều đó trong một khoảng thời gian hợp lý (bỏ qua lỗi), vì vậy không phải là không thể.

EDIT: Để tham khảo trong tương lai, đây là một cuộc thảo luận khác có một ví dụ thú vị.


125
Và đó, những đứa trẻ, là lý do tại sao chúng tôi dạy cho bạn lý thuyết tính toán. ;)
Raphael

7
Đây không phải là vấn đề tính toán vì con người cũng không thể quyết định trong mọi trường hợp. Đó là một vấn đề đầy đủ; báo cáo thỏa thuận chứa thông tin, nếu bị xóa, không thể phục hồi hoàn toàn bằng phân tích trừ khi phân tích đó bao gồm thông tin về môi trường triển khai và hoạt động dự kiến, mà mã nguồn C không chứa.
Nat

41
Không, đó là một vấn đề tính toán. Không thể chắc chắn liệu một mảnh bộ nhớ nhất định có nên được giải phóng hay không. Đối với một chương trình cố định, không có đầu vào của người dùng hoặc nhiễu bên ngoài khác.
Andrej Bauer

1
Bình luận không dành cho thảo luận mở rộng; cuộc trò chuyện này đã được chuyển sang trò chuyện . Tất cả các ý kiến ​​không giải quyết cụ thể câu hỏi và làm thế nào để cải thiện nó sẽ bị xóa ngay lập tức.
Raphael

2
@BorisTreukhov, vui lòng mang nó đến phòng chat. Không, tôi không nghĩ Andrej đang nói rằng phân tích thoát là "không thể" (mặc dù việc xác định chính xác điều đó có nghĩa là gì trong bối cảnh này là một chút không rõ ràng đối với tôi). Phân tích thoát hoàn toàn chính xác không thể giải quyết được. Để tất cả: xin vui lòng mang nó đến phòng chat . Vui lòng chỉ gửi bình luận ở đây nhằm cải thiện câu hỏi - thảo luận và bình luận khác nên được đăng trong phòng chat.
DW

Câu trả lời:


80

Bởi vì không thể xác định được liệu chương trình có sử dụng lại bộ nhớ hay không. Điều này có nghĩa là không có thuật toán nào có thể xác định chính xác khi nào cần gọi free()trong mọi trường hợp, điều đó có nghĩa là bất kỳ trình biên dịch nào cố gắng thực hiện điều này nhất thiết sẽ tạo ra một số chương trình bị rò rỉ bộ nhớ và / hoặc một số chương trình tiếp tục sử dụng bộ nhớ đã được giải phóng. Ngay cả khi bạn đảm bảo rằng trình biên dịch của bạn không bao giờ thực hiện lần thứ hai và cho phép lập trình viên chèn các cuộc gọi để free()sửa các lỗi đó, thì biết khi nào nên gọi free()trình biên dịch đó sẽ còn khó hơn khi biết khi nào nên free()sử dụng trình biên dịch không thử giúp đỡ.


12
Chúng tôi có một câu hỏi bao gồm khả năng của con người để giải quyết các vấn đề không thể giải quyết được . Tôi không thể cho bạn một ví dụ về một chương trình sẽ được biên dịch không chính xác bởi vì điều đó phụ thuộc vào thuật toán mà trình biên dịch sử dụng. Nhưng bất kỳ thuật toán nào cũng sẽ tạo ra đầu ra không chính xác cho vô số chương trình khác nhau.
David Richerby

1
Bình luận không dành cho thảo luận mở rộng; cuộc trò chuyện này đã được chuyển sang trò chuyện .
Gilles 'SO- ngừng trở nên xấu xa'

2
Các bạn, hãy mang nó đi trò chuyện . Tất cả mọi thứ không liên quan trực tiếp đến câu trả lời và cách cải thiện nó sẽ bị xóa.
Raphael

2
Nói chung, rất nhiều thứ mà trình biên dịch làm một cách vui vẻ là không thể giải quyết được; chúng ta sẽ không đi đến bất cứ nơi nào trong thế giới biên dịch nếu chúng ta luôn chuyển sang định lý của Rice.
Tikhon Jelvis

3
Điều này là không liên quan. Nếu nó là không thể đối với tất cả các trình biên dịch, thì nó cũng không thể giải quyết được cho tất cả mọi người. Tuy nhiên, chúng tôi hy vọng con người chèn free()chính xác.
Paul Draper

53

Như David Richerby đã lưu ý đúng, vấn đề nói chung là không thể giải quyết được. Đối tượng sống là một tài sản toàn cầu của chương trình và nói chung có thể phụ thuộc vào các yếu tố đầu vào của chương trình.

Ngay cả bộ sưu tập rác động chính xác là một vấn đề không thể giải quyết! Tất cả những người thu gom rác trong thế giới thực đều sử dụng khả năng tiếp cận như một xấp xỉ bảo thủ cho dù có cần một đối tượng được phân bổ trong tương lai hay không. Đó là một xấp xỉ tốt, nhưng dù sao nó cũng là một xấp xỉ.

Nhưng điều đó chỉ đúng nói chung. Một trong những cảnh sát khét tiếng nhất trong ngành kinh doanh khoa học máy tính là "nói chung là không thể, vì vậy chúng tôi không thể làm gì được". Ngược lại, có nhiều trường hợp có thể thực hiện một số bước tiến.

Việc triển khai dựa trên việc đếm tham chiếu rất gần với "trình biên dịch chèn trình biên dịch" sao cho khó có thể phân biệt được. Đếm tham chiếu tự động của LLVM (được sử dụng trong Objective-CSwift ) là một ví dụ nổi tiếng.

Suy luận khu vựcthu gom rác thời gian biên dịch là các lĩnh vực nghiên cứu đang hoạt động hiện nay. Nó trở nên dễ dàng hơn nhiều trong các ngôn ngữ khai báo như MLMercury , nơi bạn không thể sửa đổi một đối tượng sau khi nó được tạo.

Bây giờ, về chủ đề con người, có ba cách chính mà con người quản lý vòng đời phân bổ theo cách thủ công:

  1. Bằng cách hiểu chương trình và vấn đề. Con người có thể đặt các đối tượng có tuổi thọ tương tự trong cùng một đối tượng phân bổ, chẳng hạn. Trình biên dịch và thu gom rác phải suy ra điều này, nhưng con người có thông tin chính xác hơn.
  2. Bằng cách chọn lọc bằng cách sử dụng lưu giữ sách không nhắm mục tiêu (ví dụ: đếm tham chiếu) hoặc các kỹ thuật phân bổ đặc biệt khác (ví dụ như các vùng) chỉ khi cần thiết. Một lần nữa, một con người có thể biết điều này trong đó một trình biên dịch phải suy ra nó.
  3. Tệ. Mọi người đều biết các chương trình triển khai trong thế giới thực có rò rỉ chậm, sau tất cả. Hoặc nếu không, đôi khi các chương trình và API nội bộ cần được cấu trúc lại theo thời gian sử dụng bộ nhớ, giảm khả năng sử dụng lại và mô đun hóa.

Bình luận không dành cho thảo luận mở rộng. Nếu bạn muốn thảo luận về khai báo vs chức năng, xin vui lòng làm điều đó trong trò chuyện .
Gilles 'SO- ngừng trở nên xấu xa'

2
Đây là câu trả lời tốt nhất cho câu hỏi (mà quá nhiều câu trả lời thậm chí không giải quyết được). Bạn có thể đã thêm một tài liệu tham khảo cho công việc tiên phong của Hans Boehm trên GC liên quan : en.wikipedia.org/wiki/Boehm_garbage_collector . Một điểm thú vị khác là tính linh hoạt của dữ liệu (hoặc tính hữu dụng theo nghĩa mở rộng) có thể được định nghĩa liên quan đến ngữ nghĩa trừu tượng hoặc mô hình thực thi. Nhưng chủ đề thực sự rộng.
babou

29

Đó là một vấn đề không hoàn hảo, không phải là vấn đề không thể giải quyết được

Mặc dù sự thật là vị trí tối ưu của các tuyên bố thỏa thuận là không thể giải quyết được, nhưng đó đơn giản không phải là vấn đề ở đây. Vì không thể áp dụng được cho cả người và trình biên dịch, nên không thể luôn luôn cố ý chọn vị trí phân bổ tối ưu, bất kể đó là quy trình thủ công hay tự động. Và vì không ai hoàn hảo, một trình biên dịch đủ tiên tiến sẽ có thể vượt trội so với con người khi đoán được các vị trí tối ưu. Vì vậy, tính không ổn định không phải là lý do tại sao chúng ta cần các tuyên bố giải quyết rõ ràng .

Có những trường hợp trong đó kiến ​​thức bên ngoài thông báo vị trí tuyên bố thỏa thuận. Việc xóa các câu lệnh đó sau đó tương đương với việc loại bỏ một phần logic hoạt động và yêu cầu trình biên dịch tự động tạo ra logic đó tương đương với việc yêu cầu nó đoán xem bạn đang nghĩ gì.

Ví dụ: giả sử bạn đang viết Vòng lặp Đọc-Đánh giá-In (REPL) : người dùng nhập vào một lệnh và chương trình của bạn sẽ thực thi nó. Người dùng có thể phân bổ / giải phóng bộ nhớ bằng cách nhập lệnh vào REPL của bạn. Mã nguồn của bạn sẽ chỉ định REPL nên làm gì cho mỗi lệnh người dùng có thể, bao gồm cả việc phân bổ khi người dùng gõ vào lệnh cho nó.

Nhưng nếu mã nguồn C không cung cấp một lệnh rõ ràng để phân bổ, thì trình biên dịch sẽ cần phải suy luận rằng nó sẽ thực hiện lệnh dellocation khi người dùng nhập lệnh thích hợp vào REPL. Là lệnh "thỏa thuận", "miễn phí", hay cái gì khác? Trình biên dịch không có cách nào để biết lệnh bạn muốn là gì. Ngay cả khi bạn lập trình theo logic để tìm từ lệnh đó và REPL tìm thấy nó, trình biên dịch không có cách nào để biết rằng nó sẽ đáp ứng với nó bằng cách xử lý trừ khi bạn nói rõ ràng với nó trong mã nguồn.

tl; dr Vấn đề là mã nguồn C không cung cấp cho trình biên dịch kiến ​​thức bên ngoài. Sự không chắc chắn không phải là vấn đề bởi vì đó là liệu quy trình là thủ công hay tự động.


3
Bình luận không dành cho thảo luận mở rộng; cuộc trò chuyện này đã được chuyển sang trò chuyện . Tất cả các ý kiến ​​khác không giải quyết cụ thể những thiếu sót của câu trả lời này và cách khắc phục chúng sẽ bị xóa ngay lập tức.
Raphael

23

Hiện tại, không có câu trả lời được đăng nào là hoàn toàn chính xác.

Tại sao trình biên dịch không tự động chèn thỏa thuận?

  1. Một số làm. (Tôi sẽ giải thích sau.)

  2. Một cách tầm thường, bạn có thể gọi free()ngay trước khi chương trình thoát. Nhưng có một nhu cầu ngụ ý trong câu hỏi của bạn để gọi free()càng sớm càng tốt.

  3. Vấn đề khi nào cần gọi free()trong bất kỳ chương trình C nào ngay khi bộ nhớ không thể truy cập được là không thể giải quyết được, tức là đối với bất kỳ thuật toán nào cung cấp câu trả lời trong thời gian hữu hạn, có một trường hợp nó không bao gồm. Điều này - và nhiều tính không ổn định khác của các chương trình tùy ý - có thể được chứng minh từ Vấn đề Ngừng .

  4. Một vấn đề không thể giải quyết không phải lúc nào cũng có thể được giải quyết trong thời gian hữu hạn bằng bất kỳ thuật toán nào, cho dù là trình biên dịch hay con người.

  5. Con người (cố gắng) viết trong một tập hợp con của các chương trình C có thể được xác minh tính chính xác của bộ nhớ bằng thuật toán của họ (chính họ).

  6. Một số ngôn ngữ hoàn thành # 1 bằng cách xây dựng # 5 vào trình biên dịch. Chúng không cho phép các chương trình sử dụng phân bổ bộ nhớ tùy ý, mà là một tập hợp con có thể quyết định của chúng. FothRust là hai ví dụ về các ngôn ngữ có phân bổ bộ nhớ hạn chế hơn C malloc(), có thể (1) phát hiện nếu một chương trình được viết bên ngoài tập hợp có thể quyết định của chúng (2) tự động chèn các giao dịch.


1
Tôi hiểu cách Rust làm điều đó. Nhưng tôi chưa bao giờ nghe nói về một Forth đã làm điều này. Bạn có thể xây dựng?
Milton Silva

2
@MiltonSilva, Forth - ít nhất là triển khai ban đầu, cơ bản nhất của nó - chỉ có một ngăn xếp, không phải là một đống. Nó thực hiện phân bổ / thỏa thuận di chuyển con trỏ ngăn xếp cuộc gọi, một nhiệm vụ mà trình biên dịch có thể dễ dàng thực hiện. Forth được tạo ra để nhắm mục tiêu phần cứng rất đơn giản và đôi khi bộ nhớ không động là tất cả những gì có thể thực hiện được. Đó rõ ràng không phải là một giải pháp khả thi cho các chương trình không tầm thường.
Paul Draper

10

"Con người làm điều đó, vì vậy nó không phải là không thể" là một ngụy biện nổi tiếng. Chúng ta không nhất thiết phải hiểu (hãy để một mình kiểm soát) những thứ chúng ta tạo ra - tiền là một ví dụ phổ biến. Chúng ta có xu hướng đánh giá quá cao (đôi khi đáng kể) cơ hội thành công của chúng ta trong các vấn đề công nghệ, đặc biệt là khi các yếu tố con người dường như vắng mặt.

Hiệu suất của con người trong lập trình máy tính rất kém và nghiên cứu về khoa học máy tính (thiếu nhiều chương trình giáo dục chuyên nghiệp) giúp hiểu tại sao vấn đề này không có cách khắc phục đơn giản. Chúng ta có thể một ngày nào đó, có lẽ không quá xa, được thay thế bằng trí tuệ nhân tạo trong công việc. Ngay cả khi đó, sẽ không có một thuật toán chung nào được phân bổ đúng, tự động, mọi lúc.


1
Sai lầm của việc chấp nhận tiền đề của sự nguỵ biện của con người và cho rằng những cỗ máy tư duy do con người tạo ra có thể vẫn không thể sai lầm (tức là tốt hơn con người) ít được biết đến nhưng hấp dẫn hơn. Giả định duy nhất mà từ đó hành động có thể tiến hành là tâm trí con người có khả năng tính toán hoàn hảo.
tự đại diện

1. Tôi chưa bao giờ nói rằng máy móc suy nghĩ có thể là không thể sai lầm. Tốt hơn con người là những gì họ đã có, trong nhiều trường hợp. 2. Kỳ vọng về sự hoàn hảo (thậm chí tiềm năng) là điều kiện tiên quyết cho hành động là một điều phi lý.
André Souza Lemos

"Chúng tôi có thể một ngày nào đó, có lẽ không quá xa, được thay thế bằng trí tuệ nhân tạo trong công việc." Điều này, đặc biệt, là vô nghĩa. Con người là nguồn gốc của ý định trong hệ thống. Không có con người, không có mục đích cho hệ thống. "Trí tuệ nhân tạo" có thể được định nghĩa là apparency của minh quyết định hiện tại thời gian của máy móc, mang lại trong thực tế bởi những quyết định thông minh của một nhà thiết kế lập trình viên hoặc hệ thống trong quá khứ. Nếu không có bảo trì ( phải được thực hiện bởi một người), AI (hoặc bất kỳ hệ thống nào không được kiểm tra và hoàn toàn tự động) sẽ thất bại.
tự đại diện

Ý định, ở con người như trong máy móc, luôn đến từ bên ngoài .
André Souza Lemos

Hoàn toàn sai sự thật. (Và ngoài ra, "bên ngoài" không xác định nguồn. ) Hoặc bạn nói rằng ý định đó không thực sự tồn tại hoặc bạn nói rằng ý định đó tồn tại nhưng không đến từ bất cứ đâu. Có lẽ bạn tin rằng ý định có thể tồn tại độc lập với mục đích? Trong trường hợp bạn hiểu nhầm từ "ý định." Dù bằng cách nào, một cuộc biểu tình trực tiếp sẽ sớm thay đổi suy nghĩ của bạn về chủ đề này. Tôi sẽ bỏ qua sau bình luận này vì một mình từ ngữ không thể mang lại hiểu biết về "ý định", vì vậy thảo luận thêm ở đây là vô nghĩa.
tự đại diện

9

Việc thiếu quản lý bộ nhớ tự động là một tính năng của ngôn ngữ.

C không phải là một công cụ để viết phần mềm dễ dàng. Nó là một công cụ để làm cho máy tính làm bất cứ điều gì bạn bảo nó làm. Điều đó bao gồm phân bổ và giải phóng bộ nhớ tại thời điểm bạn chọn. C là ngôn ngữ cấp thấp bạn sử dụng khi bạn muốn điều khiển máy tính chính xác hoặc khi bạn muốn thực hiện mọi thứ theo cách khác với những gì các nhà thiết kế thư viện / ngôn ngữ tiêu chuẩn mong đợi.


Bình luận không dành cho thảo luận mở rộng; cuộc trò chuyện này đã được chuyển sang trò chuyện .
DW

2
Làm thế nào đây là một câu trả lời cho câu hỏi (phần CS của)?
Raphael

6
@Raphael Khoa học máy tính không có nghĩa là chúng ta nên tìm kiếm những câu trả lời kỹ thuật tối nghĩa. Trình biên dịch làm nhiều điều không thể trong trường hợp chung. Nếu chúng ta muốn quản lý bộ nhớ tự động, chúng ta có thể thực hiện nó theo nhiều cách. C không làm như vậy, vì nó không phải là để làm.
Jouni Sirén

9

Vấn đề chủ yếu là một cổ vật lịch sử, không phải là không thể thực hiện.

Cách mà hầu hết các trình biên dịch C xây dựng mã là để trình biên dịch chỉ nhìn thấy từng tệp nguồn tại một thời điểm; nó không bao giờ nhìn thấy toàn bộ chương trình cùng một lúc. Khi một tệp nguồn gọi một hàm từ một tệp nguồn khác hoặc một thư viện, tất cả trình biên dịch nhìn thấy là tệp tiêu đề có kiểu trả về của hàm, không phải là mã thực tế của hàm. Điều này có nghĩa là khi có một hàm trả về một con trỏ, trình biên dịch không có cách nào để biết liệu bộ nhớ mà con trỏ đang trỏ có cần được giải phóng hay không. Thông tin để quyết định không được hiển thị cho trình biên dịch tại thời điểm đó. Một lập trình viên con người, mặt khác, có thể tự do tra cứu mã nguồn của hàm hoặc tài liệu để tìm hiểu những gì cần phải làm với con trỏ.

Nếu bạn nhìn vào các ngôn ngữ cấp thấp hiện đại hơn như C ++ 11 hoặc Rust, bạn sẽ thấy rằng họ chủ yếu giải quyết vấn đề bằng cách làm cho quyền sở hữu bộ nhớ rõ ràng trong loại con trỏ. Trong C ++, bạn sẽ sử dụng unique_ptr<T>thay vì đơn giản T*để giữ bộ nhớ và unique_ptr<T>đảm bảo rằng bộ nhớ sẽ được giải phóng khi đối tượng đến cuối phạm vi, không giống như đồng bằng T*. Lập trình viên có thể trao bộ nhớ từ cái này unique_ptr<T>sang cái khác, nhưng chỉ có thể có một cái unique_ptr<T>chỉ vào bộ nhớ. Vì vậy, luôn luôn rõ ràng ai sở hữu bộ nhớ và khi nào nó cần được giải phóng.

C ++, vì lý do tương thích ngược, vẫn cho phép quản lý bộ nhớ thủ công kiểu cũ và do đó tạo ra các lỗi hoặc cách để tránh sự bảo vệ của a unique_ptr<T>. Rust thậm chí còn nghiêm ngặt hơn ở chỗ nó thực thi các quy tắc sở hữu bộ nhớ thông qua các lỗi biên dịch.

Đối với tính không ổn định, vấn đề tạm dừng và tương tự, vâng, nếu bạn tuân theo ngữ nghĩa C, không thể quyết định tất cả các chương trình khi bộ nhớ sẽ được giải phóng. Tuy nhiên, đối với hầu hết các chương trình thực tế, không phải bài tập học thuật hay phần mềm lỗi, hoàn toàn có thể quyết định khi nào miễn phí và khi nào không. Đó là lý do duy nhất tại sao con người có thể tìm ra khi nào nên giải phóng hay không ở nơi đầu tiên.


Bình luận không dành cho thảo luận mở rộng; cuộc trò chuyện này đã được chuyển sang trò chuyện .
Raphael

6

Các câu trả lời khác đã tập trung vào việc có thể thực hiện thu gom rác hay không, một số chi tiết về cách thực hiện và một số vấn đề.

Một vấn đề chưa được đề cập đến là sự chậm trễ không thể tránh khỏi trong việc thu gom rác. Trong C, khi lập trình viên gọi free (), bộ nhớ đó ngay lập tức có sẵn để sử dụng lại. (Về lý thuyết ít nhất!) Vì vậy, một lập trình viên có thể giải phóng cấu trúc 100 MB của họ, phân bổ cấu trúc 100 MB khác một mili giây sau đó và hy vọng việc sử dụng bộ nhớ tổng thể sẽ giữ nguyên.

Điều này không đúng với bộ sưu tập rác. Các hệ thống thu gom rác có một số chậm trễ trong việc trả lại bộ nhớ không sử dụng cho đống, và điều này có thể là đáng kể. Nếu cấu trúc 100 MB của bạn vượt quá phạm vi và một phần nghìn giây sau đó, chương trình của bạn sẽ thiết lập cấu trúc 100 MB khác, bạn có thể mong đợi một cách hợp lý hệ thống của bạn sẽ sử dụng 200 MB trong một thời gian ngắn. "Khoảng thời gian ngắn" đó có thể là mili giây hoặc giây tùy theo hệ thống, nhưng vẫn có độ trễ.

Nếu bạn đang chạy trên PC với nhiều hợp đồng RAM và bộ nhớ ảo, tất nhiên có lẽ bạn sẽ không bao giờ nhận thấy điều này. Nếu bạn đang chạy trên một hệ thống có nhiều tài nguyên hạn chế hơn (ví dụ: hệ thống nhúng hoặc điện thoại), đây là điều bạn cần thực hiện nghiêm túc. Đây không chỉ là lý thuyết - Cá nhân tôi đã thấy điều này tạo ra sự cố (như khi gặp sự cố loại thiết bị) khi làm việc trên hệ thống WinCE sử dụng .NET Compact Framework và phát triển trong C #.


Về lý thuyết, bạn có thể chạy một GC trước mỗi lần phân bổ.
adrianN

4
@adrianN Nhưng trong thực tế, điều này không được thực hiện bởi vì nó sẽ là tinh thần. Quan điểm của Graham vẫn đứng vững: Các GC luôn phải chịu một chi phí đáng kể, về mặt thời gian chạy hoặc về bộ nhớ thặng dư cần thiết. Bạn có thể điều chỉnh số dư này theo hướng cực đoan nhưng về cơ bản bạn không thể loại bỏ chi phí.
Konrad Rudolph

"Độ trễ" khi bộ nhớ được giải phóng là vấn đề trong hệ thống bộ nhớ ảo hơn là trong hệ thống có tài nguyên hạn chế. Trong trường hợp trước, có thể tốt hơn là chương trình sử dụng 100MB hơn 200 MB ngay cả khi hệ thống có sẵn 200 MB , nhưng trong trường hợp sau, sẽ không có lợi ích gì khi chạy GC sớm hơn cần thiết trừ khi sự chậm trễ sẽ được chấp nhận hơn trong một số trường hợp các bộ phận của mã hơn trong những người khác.
supercat

Tôi không thấy cách này cố gắng trả lời (phần CS của câu hỏi).
Raphael

1
@Raphael Tôi đã giải thích một vấn đề được công nhận rõ ràng với nguyên tắc thu gom rác, đó là (hoặc nên được) dạy trong CS là một trong những nhược điểm cơ bản của nó. Tôi thậm chí đã đưa ra kinh nghiệm cá nhân của mình khi thấy điều này trong thực tế, để cho thấy rằng đó không phải là vấn đề lý thuyết đơn thuần. Nếu bạn không hiểu điều gì về điều này, tôi rất vui được nói chuyện với bạn để nâng cao kiến ​​thức của bạn về chủ đề này.
Graham

4

Câu hỏi đặt ra một thỏa thuận là thứ mà lập trình viên phải suy ra từ các phần khác của mã nguồn. Không phải vậy. "Tại thời điểm này trong chương trình, tham chiếu bộ nhớ FOO không còn hữu ích nữa" là thông tin chỉ được biết đến trong tâm trí của lập trình viên cho đến khi nó được mã hóa thành (bằng ngôn ngữ thủ tục) một tuyên bố giải quyết.

Về mặt lý thuyết, nó không khác biệt so với bất kỳ dòng mã nào khác. Tại sao trình biên dịch không tự động chèn "Tại thời điểm này trong chương trình, hãy kiểm tra thanh ghi BAR cho đầu vào" hoặc "nếu lệnh gọi hàm trả về giá trị khác, thoát chương trình con hiện tại" ? Từ quan điểm của nhà soạn nhạc, lý do là "không đầy đủ", như thể hiện trong câu trả lời này . Nhưng bất kỳ chương trình nào cũng phải chịu đựng sự không hoàn hảo khi lập trình viên đã không nói với nó mọi thứ anh ta biết.

Trong cuộc sống thực, các thỏa thuận là công việc nặng nề hoặc luồn lách; bộ não của chúng ta tự động điền chúng vào và càu nhàu về nó, và tình cảm "trình biên dịch có thể làm tốt như vậy hoặc tốt hơn" là đúng. Tuy nhiên, về lý thuyết, đó không phải là trường hợp, mặc dù may mắn thay, các ngôn ngữ khác cho chúng ta nhiều sự lựa chọn hơn về lý thuyết.


4
"'Tại thời điểm này trong chương trình, tham chiếu bộ nhớ FOO không còn hữu ích nữa' là thông tin chỉ được biết đến trong tâm trí của lập trình viên" - điều đó rõ ràng sai. a) Đối với nhiều FOO, thật tầm thường khi tìm hiểu điều này, ví dụ các biến cục bộ với ngữ nghĩa giá trị. b) Bạn đề nghị rằng lập trình viên luôn biết điều này, đây rõ ràng là một giả định quá lạc quan; nếu đó là sự thật, chúng tôi sẽ không gặp lỗi nghiêm trọng do xử lý bộ nhớ kém là phần mềm quan trọng về bảo mật. Mà, than ôi, chúng tôi làm.
Raphael

Tôi chỉ gợi ý rằng ngôn ngữ được thiết kế cho trường hợp các lập trình viên không biết FOO là không hữu ích nữa. Tôi đồng ý, rõ ràng, điều này thường không đúng và đó là lý do tại sao chúng ta cần phải có phân tích tĩnh và / hoặc thu gom rác. Mà, hooray, chúng tôi làm. Nhưng câu hỏi của OP là, khi nào những thứ đó không có giá trị như deallocs được mã hóa bằng tay?
Travis Wilson

4

Những gì được thực hiện: Có bộ sưu tập rác và có các trình biên dịch sử dụng tính năng tham chiếu (Objective-C, Swift). Những người thực hiện đếm tham chiếu cần sự giúp đỡ của lập trình viên bằng cách tránh các chu kỳ tham chiếu mạnh.

Các thực câu trả lời cho "tại sao" là nhà văn biên dịch đã không tìm ra một cách đó là đủ tốt và đủ nhanh để làm cho nó có thể sử dụng trong một trình biên dịch. Vì các trình soạn thảo trình biên dịch thường khá thông minh, bạn có thể kết luận rằng rất khó để tìm ra một cách đủ tốt và đủ nhanh.

Một trong những lý do mà nó rất, rất khó là tất nhiên là nó không thể giải quyết được. Trong khoa học máy tính, khi chúng ta nói về "tính quyết định", chúng ta có nghĩa là "đưa ra quyết định đúng đắn". Các lập trình viên con người tất nhiên có thể dễ dàng quyết định nơi phân bổ bộ nhớ, bởi vì họ không bị giới hạn trong các quyết định chính xác . Và họ thường đưa ra quyết định sai.


Tôi không thấy một đóng góp ở đây.
babou

3

Trong các ngôn ngữ như C, lập trình viên dự kiến ​​sẽ chèn các cuộc gọi miễn phí. Tại sao trình biên dịch không làm điều này tự động?

Bởi vì thời gian tồn tại của khối bộ nhớ là quyết định của lập trình viên chứ không phải của nhà biên dịch.

Đó là nó. Đây là thiết kế của C. Compiler không thể biết ý định phân bổ khối bộ nhớ là gì. Con người có thể làm điều đó, bởi vì họ biết mục đích của mọi khối bộ nhớ và khi mục đích này được phục vụ để nó có thể được giải phóng. Đó là một phần của thiết kế chương trình được viết.

C là ngôn ngữ cấp thấp, do đó, các trường hợp chuyển một khối bộ nhớ của bạn sang một quy trình khác hoặc thậm chí cho một bộ xử lý khác là khá thường xuyên. Trong trường hợp cực đoan, một lập trình viên có thể cố tình phân bổ một đoạn bộ nhớ và không bao giờ sử dụng nó một lần nữa chỉ để gây áp lực bộ nhớ lên các phần khác của hệ thống. Trình biên dịch không có cách nào để biết nếu khối vẫn còn cần thiết.


-1

Trong các ngôn ngữ như C, lập trình viên dự kiến ​​sẽ chèn các cuộc gọi miễn phí. Tại sao trình biên dịch không làm điều này tự động?

Trong C và nhiều ngôn ngữ khác, thực sự có một cơ sở để làm cho trình biên dịch thực hiện tương đương với điều này trong những trường hợp rõ ràng vào thời gian biên dịch khi cần thực hiện: sử dụng các biến có thời lượng tự động (tức là các biến cục bộ thông thường) . Trình biên dịch có trách nhiệm sắp xếp đủ không gian cho các biến đó và giải phóng không gian đó khi thời gian tồn tại (được xác định rõ) của chúng kết thúc.

Với các mảng có độ dài thay đổi là một tính năng C kể từ C99, về nguyên tắc, các đối tượng có thời lượng tự động phục vụ, về cơ bản, tất cả các hàm trong C mà các đối tượng được phân bổ động của thời lượng tính toán đều thực hiện. Trong thực tế, tất nhiên, việc triển khai C có thể đặt ra các giới hạn thực tế đáng kể đối với việc sử dụng VLA - tức là kích thước của chúng có thể bị giới hạn do được phân bổ trên ngăn xếp - nhưng đây là một xem xét thực hiện, không phải là xem xét thiết kế ngôn ngữ.

Những đối tượng có mục đích sử dụng ngăn chặn cho chúng thời lượng tự động chính xác là những đối tượng có tuổi thọ không thể được xác định tại thời điểm biên dịch.

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.