7

Có bất kỳ ví dụ điển hình nào thể hiện sự rò rỉ bộ mô tả tệp trong Android không? Tôi đọc một nơi nào đó mà nó xảy ra nếu chúng ta không đóng các dòng ví dụ FileInputStream hoặc FileOutputStream nhưng tôi không thể tìm thấy bất kỳ ví dụ tham khảo tốt nào thể hiện nó.Ví dụ về rò rỉ mô tả tệp?

Vui lòng chia sẻ một số blog/đoạn mã. cảm ơn bạn!

+1

Chỉ cần mở một loạt tệp hoặc cổng mà không đóng? Sau một vài nghìn cửa sổ ngừng cung cấp cho họ. Tương tự như các hệ điều hành khác. – Ordous

+0

@Ordous, cảm ơn bạn đã trả lời nhanh chóng của bạn. Bạn có thể vui lòng đăng đoạn mã hoạt động của nó – VicJordan

Trả lời

0
InputStream in; 
try { 
    in = new BufferedInputStream(socket.getInputStream()); 

    // Do your stuff with the input stream 
} catch (Exception e) { 
    // Handle your exception 
} finally { 
    // Close the stream here 
    if (in != null) { 
     try { 
      in.close(); 
     } catch (IOException e) { 
      Log.e(TAG, "Unable to close stream: " + e); 
     } 
    } 
} 

Ý tưởng là đóng bộ mô tả tệp của bạn trong khối finally. Cho dù bạn hoàn tất thành công hay ngoại lệ, trình mô tả tệp sẽ được đóng lại đúng cách.

Bây giờ, nếu bạn đang tìm kiếm điều gì đó để chứng minh cách KHÔNG làm điều này đúng cách, chỉ cần quấn mã này vào vòng while(1), hãy ghi chú dòng in.close() và đặt break; vào khối catch của bạn để khi nó thổi bạn sẽ thoát khỏi vòng lặp vô hạn của mình.

+0

1) Câu hỏi này được gọi là "Ví dụ về trình mô tả tệp mô tả", không phải "làm cách nào để đóng luồng đúng cách". Bạn thậm chí không làm điều đó một cách tốt nhất.2) * chỉ quấn mã này trong một vòng lặp (1) * không đủ điều kiện là "rò rỉ" (như trong "mất vĩnh viễn tài nguyên vĩnh viễn") 3) Có một cơ hội khá tốt, việc tạo dấu vết sẽ được theo sau bằng thẻ GC, sẽ nhanh chóng hoàn thành hầu hết các luồng "bị rò rỉ". – user1643723

+1

Tôi xin lỗi, tôi đoán tôi không hiểu câu hỏi của bạn. Tuy nhiên, xem xét bạn đã có câu hỏi này lên trong một tháng, với một tiền thưởng, và không ai trả lời nó, tôi có lẽ không phải là người duy nhất không hiểu những gì bạn đang yêu cầu. Chúc bạn may mắn. – Joboodi

-1
InputStream in; 

try { 

    in = new FileInputStream(new File("abc"); 


    in.read(); // Do some stuff with open fileinputstream 
    // If an exception is generated, inputstream object will not be closed 
    // as the next statement will not be executed, instead jumping to 
    // the catch block. this will cause a leak of the fd assigned to file 
    // "abc" while opening it 
    in.close()' 
    } catch (Exception e) { 

    // Handle your exception 

    } 
6

Vì Dalvik của FileInputStream sẽ close itself when it is garbage collected (điều này cũng đúng cho OpenJDK/Oracle) nó ít phổ biến hơn bạn nghĩ để thực sự rò rỉ file descriptor. Tất nhiên, các mô tả tập tin sẽ bị "rò rỉ" cho đến khi GC chạy như vậy tùy thuộc vào chương trình của bạn có thể mất một thời gian trước khi chúng được khai hoang.

Để thực hiện một sự rò rỉ vĩnh viễn hơn, bạn sẽ phải ngăn chặn luồng rác được thu thập bằng cách giữ một tham chiếu đến nó ở đâu đó trong bộ nhớ.

Dưới đây là một ví dụ ngắn mà tải một tập tin thuộc tính mỗi 1 giây và theo dõi mỗi khi nó đã thay đổi:

public class StreamLeak { 

    /** 
    * A revision of the properties. 
    */ 
    public static class Revision { 

     final ZonedDateTime time = ZonedDateTime.now(); 
     final PropertiesFile file; 

     Revision(PropertiesFile file) { 
      this.file = file; 
     } 
    } 

    /* 
    * Container for {@link Properties} that implements lazy loading. 
    */ 
    public static class PropertiesFile { 

     private final InputStream stream; 
     private Properties properties; 

     PropertiesFile(InputStream stream) { 
      this.stream = stream; 
     } 

     Properties getProperties() { 
      if(this.properties == null) { 
       properties = new Properties(); 
       try { 
        properties.load(stream); 
       } catch(IOException e) { 
        e.printStackTrace(); 
       } 
      } 
      return properties; 
     } 

     @Override 
     public boolean equals(Object o) { 
      if(o instanceof PropertiesFile) { 
       return ((PropertiesFile)o).getProperties().equals(getProperties()); 
      } 
      return false; 
     } 
    } 

    public static void main(String[] args) throws IOException, InterruptedException { 
     URL url = new URL(args[0]); 
     LinkedList<Revision> revisions = new LinkedList<>(); 
     // Loop indefinitely 
     while(true) { 
      // Load the file 
      PropertiesFile pf = new PropertiesFile(url.openStream()); 
      // See if the file has changed 
      if(revisions.isEmpty() || !revisions.getLast().file.equals(pf)) { 
       // Store the new revision 
       revisions.add(new Revision(pf)); 
       System.out.println(url.toString() + " has changed, total revisions: " + revisions.size()); 
      } 
      Thread.sleep(1000); 
     } 
    } 
} 

Do lười tải chúng tôi giữ InputStream trong PropertiesFile mà sẽ được lưu giữ bất cứ khi nào chúng tôi tạo một bản chỉnh sửa mới và vì chúng tôi không bao giờ đóng luồng, chúng tôi sẽ rò rỉ các bộ mô tả tệp tại đây.

Bây giờ, những file descriptor mở sẽ được đóng lại bởi hệ điều hành khi chương trình kết thúc, nhưng miễn là chương trình đang chạy, nó sẽ tiếp tục bị rò rỉ file descriptor như có thể thấy bằng cách sử dụng lsof:

$ lsof | grep pf.properties | head -n 3 
java 6938 raniz 48r  REG 252,0 0 262694 /tmp/pf.properties 
java 6938 raniz 49r  REG 252,0 0 262694 /tmp/pf.properties 
java 6938 raniz 50r  REG 252,0 0 262694 /tmp/pf.properties 
$ lsof | grep pf.properties | wc -l  
431 

Và nếu chúng ta buộc các GC để chạy chúng ta có thể thấy rằng hầu hết trong số này được trả về:

$ jcmd 6938 GC.run 
6938: 
Command executed successfully 
$ lsof | grep pf.properties | wc -l 
2 

hai mô tả còn lại là những người được lưu giữ trong Revision s.

Tôi đã chạy trên máy tính Ubuntu của mình nhưng đầu ra sẽ trông tương tự nếu chạy trên Android.