内存泄漏之未关闭文件流

如果Android开启严格模式情况下会监控APP是否存在未关闭文件流,如果监控到存在未关闭文件流情况会报以下错误:

A resource was acquired at attached stack trace but never released. 
See java.io.Closeable for information on avoiding resource leaks.
                                                                
java.lang.Throwable: Explicit termination method 'close' not called
                                                                    
at dalvik.system.CloseGuard.open(CloseGuard.java:180)
                                                                
at java.io.FileInputStream.<init>(FileInputStream.java:147)

出现这种情况基本是流对象如FileInputStream没有调用close(),或者try{}catch{},没有调用finally()

对于这种问题有三种解决方案:

  1. Java 7 之后,可以使用try-with-resource方式处理
  2. Java最基础的手动关闭的形式try-catch-finally
  3. Kotlin使用use函数

使用try-with-resource方式

Java 7 之后,可以使用try-with-resource方式处理,示例代码如下

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

// 自定义类实现AutoCloseable接口
public class MyFileInputStream extends FileInputStream implements AutoCloseable {

    public MyFileInputStream(File file) throws IOException {
        super(file);
    }

    @Override
    public void close() throws IOException {
        // 重写close方法
        System.out.println("Closing MyFileInputStream");
        super.close();
    }
}

public class Test {

    public static void main(String[] args) {
        // 使用try-with-resources语句自动关闭资源
        try (MyFileInputStream fis = new MyFileInputStream(new File("test.txt"))) {
            // 在try块中使用资源
            int data = fis.read();
            while (data != -1) {
                System.out.print((char) data);
                data = fis.read();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

try-catch-finally

使用Java最基础的手动关闭的形式try-catch-finally,示例代码:

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

public void saveFile(boolean externalStorage) {
    String s = "12345";
    File file;
    FileOutputStream fos = null;
    try {
        file = externalStorage ? new File(getExternalFilesDir(null), "log") : new File(getFilesDir(), "log");
        fos = new FileOutputStream(file);
        fos.write(s.getBytes());
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        // 关闭文件流
        if (fos != null) {
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

使用use函数

use函数是kotlin标准库中的一个扩展函数,它可以用于自动关闭实现了CloseableAutoCloseable接口的资源。这些接口定义了一个close()方法,用于释放资源。例如,文件流,网络连接,数据库连接等都是需要关闭的资源。

use函数的定义如下:

public inline fun <T : AutoCloseable?, R> T.use(block: (T) -> R): R

使用 use函数读取文件示例代码:

import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException

fun copyFile(source: File, target: File) {
    // 使用use函数自动关闭输入流和输出流
    FileInputStream(source).use { input ->
        FileOutputStream(target).use { output ->
            // 在use块中使用输入流和输出流
            val buffer = ByteArray(1024)
            var bytes = input.read(buffer)
            while (bytes >= 0) {
                output.write(buffer, 0, bytes)
                bytes = input.read(buffer)
            }
        }
    }
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容