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.
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
@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