最近在学习GC,接触了一个新概念“内存泄露”,之前也听过这个概念,但是没放在心上。但这一次不一样,看看后果感谢很严重。看了一些文章,其中都提到的一个典型场景就是资源未及时关闭导致的内存泄露,回想一下,之前我用Spring Boot的MultipartFile实现文件上传时,没有主动关闭过资源,那会不会也导致内存泄露呢,带着这样的疑问,我开始了今天这篇文章。。。

1 使用MultipartFile的transferTo,是否需主动关闭资源

跟踪源码后发现,最终调用的是File类的renameTo方法,这个方法底层是通过本地方法实现的,在Java代码中没有涉及资源打开和关闭的代码,所以不需要主动关闭资源。

2 使用FileCopyUtils.copy(in, out)是否需主动关闭资源

从FileCopyUtils的源码可以看出,在方法内部对输入和输出都分别进行了关闭,所以我们如果调用了copy方法,不再需要主动关闭资源。

public static int copy(InputStream in, OutputStream out) throws IOException {
    Assert.notNull(in, "No InputStream specified");
    Assert.notNull(out, "No OutputStream specified");
    int var2;
    try {
        var2 = StreamUtils.copy(in, out);
    } finally {
        close(in);
        close(out);
    return var2;

3 MultipartFile的inputstream使用后,是否需主动关闭

如果我既不用MultipartFile的transferTo()方法,也不用FileCopyUtils的copy()方法,用inputstream的方式进行文件拷贝呢?下边是实例代码

public String fileUpload(@Validated FileUploadVo fileUploadVo) throws IOException {
    log.info("入参:{}", fileUploadVo);
    MultipartFile file = fileUploadVo.getFile();
    String fileName = UUID.randomUUID().toString() + "-" + file.getOriginalFilename();
    File newFile = new File("D://upload/" + fileName);
    // 手动获取输入、输出流
    FileOutputStream outputStream = new FileOutputStream(newFile);
    InputStream inputStream = file.getInputStream();
    byte[] bytes = new byte[1024 * 1024];
    int read = inputStream.read(bytes);
    while (read != -1) {
        outputStream.write(bytes, 0, read);
        read = inputStream.read(bytes);
    outputStream.flush();
    // 流未主动关闭
    return "success";

为了验证是否会造成内存泄露,我们需要做一些基本的配置,实验步骤如下:

3.1 设置虚拟机参数,Debug模式重启项目

  • 参数:-Xmx20M -Xms20M

3.2 提交文件上传请求

  • 1. 提交一次文件上传,进入方法内部
  • 2. 执行到此处,观察堆中实例个数
  • 3. 方法释放,执行100次请求,看看结果,实例数和预期不符,从结果来看,即使不手动关闭InputStream,也能被GC回收

结论:不手动关闭FileInputStream,不会造成内存泄露这样严重的问题(这个地方写的不对的话,欢迎指正)。这个方面有很多大神也都写文章提过,不主动关闭资源是非常不好的习惯,会浪费系统资源。比如可参考如下文章:

https://cloud.tencent.com/developer/article/1347627

补充:FileInputStream重新的finalize方法

protected void finalize() throws IOException {
    if ((fd != null) &&  (fd != FileDescriptor.in)) {
        /* if fd is shared, the references in FileDescriptor
         * will ensure that finalizer is only called when
         * safe to do so. All references using the fd have
         * become unreachable. We can call close()
        close();

很多工具类和高级别的API对资源的关闭做了考虑,我们写代码的时候不再需要关注资源关闭方面的问题,如果使用java更基础的API,则需要考虑一下资源关闭的问题。日常使用过程中还是要养成良好的习惯,要不然会被人家笑话的。

最近在学习GC,接触了一个新概念“内存泄露”,之前也听过这个概念,但是没放在心上。但这一次不一样,看看后果感谢很严重。关于内存泄露的一个典型场景就是资源未及时关闭导致的内存泄露,回想一下,之前我写文件上传的代码,没有主动关闭过资源,那会不会也导致内存泄露呢,带着这样的疑问,我开始了今天这篇文章。。。1 MultipartFile文件上传,是否需主动关闭资源2 使用FileCopyUtils.copy(in, out)是否需主动关闭资源从FileCopyUtils的源码可以看出,在方法内部对输
MultipartFile.getInputStream打开流之后,是否需要关闭呢? 因为也继承了AutoCloseable接口。 从AutoCloseable的说明里可知它是为了更好的管理资源,也就是及时释放资源,当一个资源类集成了它并且实现了close方法,在使用try-catch-resources语法创建的资源抛出异常后,JVM自动调用close 方法进行资源释放,当没有抛出异常正常退出try-block时候也调用close方法。 有些文章说只要对象销毁时,就调用close方法释放流资源。
关于对multipartFile的理解 最近一直在做文件上传的操作,一直使用,在这里给梳理整理下,再加上自己的理解,仅供参考: MultipartFile 这个类一般是用来接受前台传过来的文件,我这里接受的大部分是图片和文档,但是效果都是一样的。 首先看下MultipartFile的代码,只是接口的代码,实现类的代码就不在这里一一体现: public interface MultipartFil...
文件上传是项目开发中最常见的功能之一 ,springMVC 可以很好的支持文件上传,但是SpringMVC上下文中默认没有装配MultipartResolver,因此默认情况下其不能处理文件上传工作。如果想使用Spring的文件上传功能,则需要在上下文中配置MultipartResolver。 前端表单要求:为了能上传文件,必须将表单的method设置为POST,并将enctype设置为multipart/form-data。只有在这样的情况下,浏览器才把用户选择的文件以二进制数据发送给服务器;
异步方法上传MultipartFile问题环境概述问题现象原因解析解决方案 前端上传Excel文件,后端通过SpringMultipartFile对象接收。 本地环境始终可以,线上环境偶尔可以。偶尔的报错提示如下 java.io.FileNotFoundException: /tmp/tomcat.6000477750703684958.8120/work/Tomcat/localhost/ROOT/upload_03540bf9_3ae6_4233_af15_cd87c5bacebf
第一列第一个字符为“d”(directory)的文件为目录文件。 创建目录文件我们用:mkdir directory 命令 删除空目录文件我们用:rmdir directory 命令 删除非空目录文件
File[] file = f.listFiles(); for(int i=0;i<file.lenght;i++){ System.out.println(file[i].getName()); spring MVC 的MultipartFileFile读取...
https://www.jianshu.com/p/520b1e292c52 最近的项目中需要实现一个上传文件并解析的功能,本来觉得难点在于解析里面10w+的用户数据,但是万万没想到问题出在了一个开始的接收参数上面。 在项目中我们使用MultipartFile来接收postman传过来的文件,然而后面又需要将文件写入InputStreamReader,进而逐行读取文件内容并写入list...
一、引言也许大家在使用流时因为未关闭、或者未正常关闭引发了很多问题。其实java7引入了自动关闭流机制,只是我们未使用而已。二、自动关闭流例子public class AutoCloseTest { public static void main(String[] args) throws IOException { //将打开流代码放到try中 try (...
问题现象:docker上运行的微服务显示no space left on device 解决历程: (1)首先用命令df -h查询docker中各个目录占据的空间,显示根目录10G空间已满。进入根目录用du -sh *命令查询,占用的空间比较少,不可能到达10G