2012-01-04 39 views
12

Tôi đã đến Java từ C++. Trong thế giới C++, chúng ta chú ý đến sự an toàn ngoại lệ, và lưu ý rằng các mutator có thể cung cấp các đảm bảo khác nhau khi đối mặt với các ngoại lệ do chính mutator tạo ra hoặc một phương thức mà nó đại diện (tối thiểu, mạnh, không ném). Việc thực hiện một phương thức có bảo đảm ngoại lệ mạnh mẽ yêu cầu một số thao tác cơ bản được đảm bảo không bao giờ ném một ngoại lệ. JLS đưa ra các câu lệnh về những phép toán nào có thể ném ra các loại ngoại lệ nào, nhưng lỗi VirtualMachineError trình bày một vấn đề. Quoth các JLS:Đảm bảo không đảm bảo VirtualMachineError

một lỗi hoặc nguồn lực hạn chế nội bộ ngăn ngừa sự ảo máy Java từ việc thực hiện ngữ nghĩa của các lập trình Java ngôn ngữ; trong trường hợp này, một thể hiện của một lớp con của VirtualMachineError bị ném.

JLS không nói thêm về VirtualMachineError. Một "lỗi nội bộ" có nghĩa là một lỗi trong JVM, vì vậy tôi không quan tâm đến trường hợp đó: khi đối mặt với các lỗi trong JVM, tất cả các phiên cược bị tắt. Nhưng còn trường hợp "giới hạn tài nguyên" thì sao? Có bất kỳ hoạt động nào được đảm bảo không bao giờ thất bại do giới hạn tài nguyên không?

+0

Điều gần nhất với câu trả lời là 'try {...} catch (Throwable t) {}'. Tất nhiên nếu bộ nhớ là kiệt sức bất kỳ tiếp tục sẽ chứng minh là gần như không thể. Bây giờ điều đó không khác trong C++. –

+2

Tôi đang trả lời câu hỏi của riêng mình. Câu hỏi thường gặp thậm chí còn khuyến khích điều này. – Raedwald

Trả lời

12

Quoth các Java Virtual Machine Specification:

đặc điểm kỹ thuật này không thể dự đoán vị trí lỗi nội bộ hoặc nguồn hạn chế có thể gặp phải và không uỷ quyền một cách chính xác khi họ có thể được báo cáo. Do đó, bất kỳ VirtualMachineError lớp con định nghĩa dưới đây có thể được ném vào bất cứ lúc nào trong thời gian hoạt động của máy ảo Java :

Trong Java do đó không đảm bảo ngoại lệ có thể được thực hiện đối với các trường hợp ngoại lệ VirtualMachineError. Tất cả các bảo đảm ngoại lệ phải tuân thủ tiêu chuẩn "... nhưng không phải nếu một số VirtualMachineError bị ném". Đây là một trong những cách mà Java khác với C++.

Điều này cũng cho thấy rằng không có nhiều điểm trong việc bắt ngoại lệ VirtualMachineError, bởi vì chương trình ở trạng thái không xác định nếu chương trình đã bị ném. Thật không may, bao gồm OutOfMemoryError ngoại lệ. Thật không may, bởi vì nếu một trong nhiều nhiệm vụ thất bại vì nó cần quá nhiều bộ nhớ, chúng tôi có thể muốn tiếp tục với các tác vụ khác.

+0

Bạn đang trả lời câu hỏi của riêng mình hay chỉ cần thêm vào câu hỏi? – skaffman

+1

Tôi đang trả lời câu hỏi của riêng mình. – Raedwald

+0

Cả VirtualMachineError và OutOfMemoryError đều là lỗi. Thay vì chỉ là sự cố, Java ném một Lỗi trong một số điều kiện bất thường. Điều đó nói rằng, không có lớp con Lỗi nào được dự định bị bắt bởi hầu hết các chương trình. Lỗi có thể được phân biệt với Ngoại lệ, có thể bị phát hiện. Các bảo đảm ngoại lệ được quảng bá bởi Herb Sutter cũng có thể được áp dụng cho Java, cho các trường hợp ngoại lệ bình thường. –

1

Nếu đó là giới hạn tài nguyên, ngay từ đầu, không có hoạt động diễn ra. Đây là liên kết cho ví dụ hoàn hảo để có VirtualMachineError. Virtual machine error

Lỗi này không giống như lỗi OutofMemoryError, tại thời điểm đó một số thao tác có thể đang diễn ra.

+0

" không có hoạt động diễn ra ". Đó sẽ là "bảo đảm ngoại trừ mạnh mẽ". Nhưng không có bảo đảm như vậy được thực hiện. – Raedwald

+0

Nếu diễn giải của tôi là chính xác, dựa trên ví dụ trên, trước khi VM khởi động, nó đã kiểm tra các tài nguyên được xác định như tham số -Xmx và nó không thể tìm thấy kích thước được xác định của bộ nhớ và lỗi ném. Tôi đồng ý với quan điểm của bạn về việc không bảo đảm, nhưng không biết tại sao. – kosa

1

Tôi thấy rằng bạn đã trả lời câu hỏi của riêng mình và tôi có thể hiểu tại sao điều này sẽ gây ngạc nhiên một chút cho bạn, đến từ nền C++ nghiêm ngặt. Đây chỉ là thực tế của các bộ nhớ được quản lý (virtual) và nó không chỉ giới hạn ở java. Bộ nhớ có thể chạy hết, khi JVM được giới hạn bao nhiêu heap nó có thể sử dụng (cấu hình trên dòng lệnh java).

Tương tự, nhưng không tương đương, trong thế giới mã C++/máy-mã sẽ là GENERAL_PROTECTION_FAULT (hoặc SEGMENTATION_FAULT nếu bạn đang sử dụng * NIX) mà bạn sẽ nhận được khi cố gắng giải quyết bộ nhớ chưa được cấp phát hoặc là bên ngoài không gian địa chỉ ảo của bạn.Cung cấp một "bảo đảm ngoại lệ mạnh" khi đối mặt với kịch bản đó cũng không kém phần khó khăn vì nguyên nhân có thể là lỗi trong mã hoặc hoàn toàn nằm ngoài tầm kiểm soát của chương trình.

+0

SEGV chỉ báo lỗi trong chương trình. Sự tương tự của nó trong Java là 'NullPointerException'. – Raedwald

+0

Tôi không thấy đây là tính năng chung của một máy ảo được quản lý. JVMS cho phép 'OutOfMemoryError' được ném ngay cả khi bạn không sử dụng' new' hoặc cố gắng tải một lớp. – Raedwald

+0

@Raedwald bạn sẽ chỉ nhận được một NPE khi bạn cố gắng tham chiếu 'null'. Bạn sẽ chỉ nhận được OutOfMemoryError sau khi bạn cố gắng phân bổ bộ nhớ nhiều hơn (hoặc bạn gọi một phương thức nào) và GC đã chạy và không đủ bộ nhớ được giải phóng. –

0

Trong Java, bạn có thể gọi Thread.stop() hoặc dừng (Throwable) bất cứ lúc nào. Hầu hết các lỗi được coi là rất quan trọng mà bạn không nên cố gắng xử lý chúng trừ khi bạn thực sự biết những gì bạn đang làm.

Đã phát triển ứng dụng Java phía máy chủ trong 12 năm, tôi có thể nói rằng tôi chưa bao giờ nghe nói đến bất kỳ ai lo lắng về các ngoại lệ ngẫu nhiên bị ném. Tôi nghi ngờ nó không phải là một vấn đề bạn cần phải lo lắng về với Java.

Bạn có thể đưa ra ví dụ về lý do tại sao bạn tin rằng bạn cần bảo đảm, vì có khả năng là một cách khác để giải quyết vấn đề?

+2

Ngoại lệ 'OutOfMemoryError' là trường hợp thú vị nhất. Như tôi đã nói trong câu trả lời của riêng tôi: Thật không may, bởi vì nếu một trong nhiều nhiệm vụ thất bại vì nó cần quá nhiều bộ nhớ, chúng tôi có thể muốn tiếp tục với các tác vụ khác. Nhưng nếu JVM có thể ném một 'OutOfMemoryError', chúng ta không thể dựa vào chương trình của chúng ta đang ở trạng thái hợp lệ khi chúng ta bắt một' OutOfMemoryError'. Điều này làm cho phương pháp try-catch-discard không đáng tin cậy. – Raedwald

+0

Đã thêm thiếu "NOT" trước "cố gắng xử lý chúng". –

+2

@Raedwald Bạn có quyền loại bỏ OOME là không đáng tin cậy.Những gì bạn phải làm là xác định bộ nhớ tối đa mà bạn mong đợi toàn bộ JVM thất bại (không chỉ giới hạn mềm) và tránh thực hiện các thao tác có thể thất bại vì bạn không biết chúng sử dụng bao nhiêu bộ nhớ. Trong trường hợp xấu hơn, bạn cần phải sử dụng một quy trình riêng biệt có thể bị giết lại bắt đầu lại theo yêu cầu. (Điều này cũng bảo vệ chống lại lỗi trong các thư viện JNI) –