Rò rỉ tài nguyên: 'in' không bao giờ bị đóng


84

Tại sao Eclipse cung cấp cho tôi sự ấm lên "Rò rỉ tài nguyên: 'in' không bao giờ được đóng" trong đoạn mã sau?

public void readShapeData() {
        Scanner in = new Scanner(System.in);
        System.out.println("Enter the width of the Rectangle: ");
        width = in.nextDouble();
        System.out.println("Enter the height of the Rectangle: ");
        height = in.nextDouble();

Câu trả lời:


69

Vì bạn không đóng Máy quét của mình

in.close();

39
Điều này sẽ đóng Scannervà tắt tiếng cảnh báo, nhưng nó cũng sẽ đóng System.inmà thông thường không mong muốn.
Stuart Cook

@StuartCook +1. Một cái gì đó để theo dõi.
Informatik01

7
Tại sao chúng ta cần đóng Máy quét? "Rò rỉ tài nguyên" có nghĩa là gì?
Erran Morad

1
@nogard: Câu trả lời của bạn này là thực sự hữu ích .. nhưng khi tôi sử dụng in.close (); .. một lần nữa nó cho thấy trong không thể được giải quyết .. tôi có một mã mà không xử lý ngoại lệ .. cảm ơn
chiếc

3
@StuartCook, bạn đã quên đề cập đến lý do tại sao việc đóng System.inthường không được mong muốn. Đó là vì bạn sẽ không thể đọc lại từ đó. I E. bạn sẽ nhận được java.util.NoSuchElementException: No line foundnếu bạn cố gắng gọi điện (new Scanner(System.in)).nextLine()chẳng hạn.
Petr Bodnár

55

Như những người khác đã nói, bạn cần gọi 'close' trên các lớp IO. Tôi sẽ nói thêm rằng đây là một điểm tuyệt vời để sử dụng thử - cuối cùng là chặn mà không cần bắt, như thế này:

public void readShapeData() throws IOException {
    Scanner in = new Scanner(System.in);
    try {
        System.out.println("Enter the width of the Rectangle: ");
        width = in.nextDouble();
        System.out.println("Enter the height of the Rectangle: ");
        height = in.nextDouble();
    } finally {
        in.close();
    }
}

Điều này đảm bảo rằng Máy quét của bạn luôn đóng, đảm bảo dọn dẹp tài nguyên thích hợp.

Tương tự, trong Java 7 trở lên, bạn có thể sử dụng cú pháp "try-with-resources":

try (Scanner in = new Scanner(System.in)) {
    ... 
}

2
Rò rỉ tài nguyên nghĩa là gì và nó sẽ ảnh hưởng đến tôi như thế nào?
Erran Morad

7
@Borat - "rò rỉ tài nguyên" ngụ ý rằng một số tài nguyên hệ thống (thường là bộ nhớ) đang bị mất hoặc lãng phí một cách không cần thiết. Thông thường, điều này sẽ ảnh hưởng đến bạn khi bạn bắt đầu nhận được lỗi OutOfMemoryErrors trong quá trình hoạt động bình thường của chương trình của bạn.
Eric Lindauer

Cảm ơn eric. Tôi biết rằng bạn có thể gây ra lỗi bằng cách nối một chuỗi vào chính nó trong một vòng lặp vô hạn. Tôi không chắc làm thế nào mà máy quét có thể gây ra lỗi đó.
Erran Morad

4
Điều gì về một thử với tài nguyên?
Dennis Meng

Cảm ơn Dennis, đã thêm.
Eric Lindauer

12

Bạn cần cuộc gọi in.close(), trong một finallykhối để đảm bảo nó xảy ra.

Từ tài liệu Eclipse, đây là lý do tại sao nó gắn cờ vấn đề cụ thể này ( tôi nhấn mạnh ):

Các lớp triển khai giao diện java.io.Closable (kể từ JDK 1.5) và java.lang.AutoClosable (kể từ JDK 1.7) được coi là đại diện cho các tài nguyên bên ngoài, sẽ được đóng bằng phương thức close (), khi chúng không còn cần thiết nữa.

Trình biên dịch Java Eclipse có thể phân tích xem mã sử dụng các kiểu như vậy có tuân thủ chính sách này hay không.

...

Trình biên dịch sẽ gắn cờ [vi phạm] với "Rò rỉ tài nguyên: 'luồng' không bao giờ bị đóng".

Giải thích đầy đủ ở đây .


7

Người ta nói với bạn rằng bạn cần phải đóng Scanner bạn khởi tạo trên System.invới Scanner.close(). Thông thường mọi người đọc nên được đóng lại.

Lưu ý rằng nếu bạn đóng System.in, bạn sẽ không thể đọc lại từ đó. Bạn cũng có thể xem qua Consolelớp học.

public void readShapeData() {
    Console console = System.console();
    double width = Double.parseDouble(console.readLine("Enter the width of the Rectangle: "));
    double height = Double.parseDouble(console.readLine("Enter the height of the Rectangle: "));
    ...
}

3
Lưu ý rằng điều System.console()này không khả dụng khi chạy một ứng dụng qua Eclipse, điều này có thể gây rắc rối trong quá trình phát triển.
Stuart Cook

6

Nếu bạn đang sử dụng JDK7 hoặc 8, bạn có thể sử dụng try-catch với các tài nguyên, thao tác này sẽ tự động đóng máy quét.

try ( Scanner scanner = new Scanner(System.in); )
  {
    System.out.println("Enter the width of the Rectangle: ");
    width = scanner.nextDouble();
    System.out.println("Enter the height of the Rectangle: ");
    height = scanner.nextDouble();
  }
catch(Exception ex)
{
    //exception handling...do something (e.g., print the error message)
    ex.printStackTrace();
}

Lưu ý rằng điều khoản bắt là không bắt buộc. Nếu bạn chỉ muốn đảm bảo tài nguyên được đóng ngay cả trong trường hợp ngoại lệ, nhưng để xử lý các ngoại lệ như trong mã gốc của OP (cụ thể là không bị bắt gì cả), bạn có thể chỉ sử dụng trynhư được hiển thị và không sử dụng một catchmệnh đề.
dùng118967

5
// An InputStream which is typically connected to keyboard input of console programs

Scanner in= new Scanner(System.in);

dòng trên sẽ gọi Constructor của lớp Scanner với đối số System.in và sẽ trả về một tham chiếu đến đối tượng mới được xây dựng.

Nó được kết nối với Luồng nhập liệu được kết nối với Bàn phím, vì vậy, ngay tại thời điểm chạy, bạn có thể sử dụng đầu vào của người dùng để thực hiện thao tác cần thiết.

//Write piece of code 

Để loại bỏ rò rỉ bộ nhớ -

in.close();//write at end of code.


3

thêm vào private static Scanner in;không thực sự khắc phục được sự cố, nó chỉ xóa cảnh báo. Làm cho máy quét tĩnh có nghĩa là nó vẫn mở mãi mãi (hoặc cho đến khi lớp được dỡ bỏ, gần như là "mãi mãi"). Trình biên dịch không cung cấp cho bạn bất kỳ cảnh báo nào nữa, vì bạn đã nói với anh ta "giữ nó mở mãi mãi". Nhưng đó không phải là những gì bạn thực sự muốn, vì bạn nên đóng tài nguyên ngay khi bạn không cần chúng nữa.

HTH, Manfred.


2

Nói chung, các phiên bản của các lớp xử lý I / O sẽ được đóng lại sau khi bạn hoàn thành chúng. Vì vậy, ở cuối mã của bạn, bạn có thể thêm in.close().


2
private static Scanner in;

Tôi đã sửa nó bằng cách khai báo dưới dạng một biến lớp Scanner tĩnh riêng. Không chắc tại sao điều đó lại khắc phục được nó nhưng đó là những gì mà nhật thực khuyên tôi nên làm.


5
bạn đã tắt tiếng cảnh báo nhưng rò rỉ tài nguyên tạo
zacheusz

1

Máy quét phải được đóng lại. Một thực tiễn tốt là đóng Độc giả, Luồng ... và loại đối tượng này để giải phóng tài nguyên và rò rỉ bộ nhớ aovid; và làm như vậy trong một khối cuối cùng để đảm bảo rằng chúng được đóng lại ngay cả khi một ngoại lệ xảy ra khi xử lý các đối tượng đó.


Câu trả lời này thực sự giúp OP biết lý do tại sao anh ta nên đóng nó. Chắc chắn, anh ấy có thể đọc tài liệu và xem " scanner.close()", nhưng câu trả lời này thực sự giúp anh ấy / cô ấy hiểu chuyện gì đang xảy ra. + 1
HyperNeutrino

1

Được rồi, nghiêm túc mà nói, trong nhiều trường hợp, đây thực sự là một lỗi. Nó cũng hiển thị trong VS Code, và người lưu ý rằng bạn đã đến cuối phạm vi bao quanh mà không đóng đối tượng máy quét, nhưng không nhận ra rằng việc đóng tất cả các bộ mô tả tệp đang mở là một phần của quá trình kết thúc. Không có rò rỉ tài nguyên vì tất cả các tài nguyên đều được dọn dẹp khi kết thúc và quá trình này sẽ biến mất, không để lại tài nguyên nào.


0
Scanner sc = new Scanner(System.in);

//do stuff with sc

sc.close();//write at end of code.

-1
in.close();
scannerObject.close(); 

Nó sẽ đóng Scannervà đóng cảnh báo.

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.