2014-04-06 14 views
9

Tôi tin rằng các luồng mở gây ra rò rỉ bộ nhớ trong java (ít nhất là java 1.6 và trước đó đã có vấn đề này).Các luồng không được tiết lộ có gây rò rỉ bộ nhớ trong java không?

Nhưng, trong khi tìm kiếm (ngay cả ở đây), tôi thấy một số người đồng ý với điều này trong khi những người khác thì không. Vì vậy, nếu tôi viết chương trình này:

import java.io.*; 
public class CreatingMemoryLeak { 

    public static void main(String args[]) 
    { 
     String s = "xxxxxxx"; 
     InputStream in = new ByteArrayInputStream(ss.getBytes()); 
     BufferedInputStream bf = new BufferedInputStream(in); 

     try { 
      while(bf.read()>0) 
      { 
       System.out.println("got it"); 
      } 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
     System.out.println("Here is a input stream " + s +" causing a memory leak"); 

    } 
} 

và nếu tôi không đóng dòng bf một cách rõ ràng, nó có gây rò rỉ bộ nhớ không?

+1

Lưu ý rằng ý tưởng của 'close' là để giải phóng tài nguyên gốc (chẳng hạn như dữ liệu được cấp phát heap C cần phải là' delete'd). Tài liệu cho 'ByteArrayInputStream' [cụ thể nói' close' không ảnh hưởng đến nó] (http://docs.oracle.com/javase/7/docs/api/java/io/ByteArrayInputStream.html#close%28%29). Vì vậy, tôi không nghĩ đó là một ví dụ tốt về những gì bạn đang thực sự yêu cầu ở đây. – Radiodef

Trả lời

4

(at least java 1.6 and earlier did had this problem).

BẤT CỨ phiên bản Java, và cho vấn đề đó, BẤT CỨ ngôn ngữ, có vấn đề này; nó không dành riêng cho Java.

Nếu bạn nắm giữ tay cầm đầu vào hoặc đầu ra cần tài nguyên hệ thống, bạn cần giải phóng chúng bất kể là gì.

Java có Closeable để biểu thị rằng trường hợp bạn giữ có thể hoặc không được, giữ tài nguyên hệ thống; nhưng trong trường hợp nó xảy ra, nếu bạn không .close(), bạn sẽ bị rò rỉ tài nguyên; nó đơn giản mà. Ví dụ:

Ví dụ: bạn có thể có phương thức có đối số InputStream; OK, tốt, nhưng đây là gì InputStream? Có phải là FileInputStream hoặc ByteArrayInputStream hoặc thậm chí là cái gì khác không? Bạn không thể biết. Việc đầu tiên cần phải được đóng đúng cách nhưng thứ hai không cần phải.

Vì vậy, những gì? .close() tất cả đều là gì, bạn không có gì để mất. Bạn có thực sự muốn có cơ hội không?

Với Java 6, bạn sẽ muốn sử dụng ổi của Closer, vì đây là cách an toàn nhất để có tất cả các nguồn lực của mình đóng (và JDK không cung cấp một công cụ như vậy):

final Closer closer = Closer.create(); 

try { 
    final InputStream in = closer.register(openInHere()); 
    final InputStream in2 = closer.register(...); 
    final OutputStream out = closer.register(...); 
    // do work with in, in2, out, other 
} catch (WhateverException e) { 
    // IF WhateverException is not an IOException and you want to rethrow... 
    // throw closer.rethrow(e, WhateverException.class); 
} finally { 
    closer.close(); // always safe 
} 

Với Java 7, bạn phải cố gắng-với-nguồn lực mà làm việc với tất cả các nguồn lực AutoCloseable (mà Closeable kéo dài):

try (
    final InputStream in = ...; 
    // etc 
) { 
    // work with AutoCloseable resources 
} catch (WhateverException e) { 
    // deal with e, rethrow if necessary 
} 

sự khác biệt chính giữa Closer và thử-với-nguồn lực là với sau này, tài nguyên sẽ được c losed trướccatch trong khi Closer sẽ đóng chúng trong finally.

Nhưng một lần nữa: đừng có cơ hội. Đóng tất cả.

28

Điều quan trọng là phải chính xác trong việc sử dụng thuật ngữ 'rò rỉ bộ nhớ' đối với Java.

Trong Java, rò rỉ bộ nhớ xảy ra khi mã của bạn giữ tham chiếu vĩnh viễn, sao cho một số đối tượng không bao giờ được thu gom rác.

Không đóng luồng không phải là rò rỉ bộ nhớ theo nghĩa này. Các luồng có nguồn gốc có trình kết thúc; GC cuối cùng sẽ đóng chúng. Trừ khi bạn giữ một tham chiếu đến luồng không được tiết lộ, nó không phải là một sự rò rỉ.

Tuy nhiên, có các loại rò rỉ khác ngoài rò rỉ bộ nhớ. Hầu hết các hệ điều hành đều hạn chế số lượng tệp đang mở.Nếu bạn không đóng các luồng của mình, GC có thể mất một thời gian rất dài để đóng chúng lại cho bạn; kết quả ròng có thể là bạn chạy ra khỏi bộ mô tả tập tin hệ thống và mã của bạn không mở được thêm một tệp nữa. Một số người sẽ gọi đây là một rò rỉ, nhưng nó không chính xác để gọi nó là một rò rỉ bộ nhớ.

+6

+1 - Đây là rò rỉ tài nguyên, không phải rò rỉ bộ nhớ. –

0

Câu trả lời tùy thuộc vào luồng.

Rò rỉ bộ nhớ chỉ đơn giản là một tình huống mà bạn giữ những thứ mà bạn không có ý định. Điều này luôn luôn là do một lỗi lập trình: một người nào đó ở đâu đó quên để phát hành ("tách" từ tất cả các tài liệu tham khảo mạnh mẽ) một số trường hợp. Những điều này thêm lên theo thời gian và sau đó bạn nhận thấy "rò rỉ". Một bộ nhớ đệm phát triển vô thời hạn là một ví dụ tốt.

Luồng, ví dụ: có thể đặt một số dữ liệu vào vùng chứa được chia sẻ (thường là tĩnh) như khóa tài nguyên, một số loại bộ nhớ cache, v.v. ngay khi mở/sử dụng. Và sau đó nó dọn sạch tài nguyên này theo phương pháp đóng. Vì vậy, bỏ qua phần cuối cùng này sẽ tạo ra rò rỉ bộ nhớ.

Trong ví dụ của bạn, phương thức ByteArrayInputStream.close() không làm gì cả, do đó, không có vấn đề gì ở đó. BufferedInputStream.close() chỉ ủy quyền cuộc gọi đến lớp được bao bọc, trong trường hợp này, một lần nữa không có vấn đề gì.

Các luồng phức tạp khác xử lý tệp, luồng mạng có thể tạo rò rỉ nếu không đóng nhưng không phổ biến. Tôi giả định rằng dòng chính nó không được giữ xung quanh nhưng còn lại để thu thập. Trong nhiều trường hợp, luồng "thông minh" thậm chí có thể khắc phục những sự giám sát này trong bộ sưu tập của chính nó và tự thực hiện việc dọn dẹp cần thiết (điều này vẫn là một tình huống bất thường mà luồng ghi rõ/thông báo ở đâu đó).

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