相关文章推荐

springboot上传大文件时内存溢出的可能解决办法

  • 在springboot中上传大文件时要考虑内存的情况,一般我们会通过在执行服务时加入-Xms512m -Xmx512m等参数加大堆内存,但这是指标不治本的,关键还是看代码处理的时候有无导致内存泄漏的原因。
    例如:
    java -Xms512m -Xmx512m -jar rent_web-1.0.0.jar
    
  • 有时候我们会需要把上传的文件再调用其他服务进行上传,即a把文件上传给b,b再把文件上传给c,那么在中间的这个转发服务如果处理不好就会导致内存溢出。
  • 下面是导致内存溢出的代码,这里溢出的原因是RequestBody的创建用了file.getBytes(),如果你继续跟进RequestBody.create就会发现最终会调用System.arraycopy来拷贝file.getBytes(),这相当于拷贝了一份,如果本来是512M,一拷贝就变成了1024M,内存肯定吃不消,于是就抛出内存溢出。
 public ApiResult<UploadResult> storeFile(MultipartFile file) throws IOException {
      	...
        String originalName= URLEncoder.encode(file.getOriginalFilename(),"utf8");
        RequestBody rb = RequestBody.create(MediaType.parse("multipart/form-data"), file.getBytes());
        MultipartBody.Part part = MultipartBody.Part.createFormData("file",originalName, rb);
        EFSService efsService = getRandEFSService();
        Response<ApiResult<UploadResult>> res = efsService.upload(part, module).execute();
     	...
  • 经过自己实践,我的思路是先把文件存到本地临时目录(其实上传文件大小超过10KB就已经会被存在本地临时目录,但由于是私有对象不可访问,当然你高兴可以用反射获得,但既然官方不开放这样的接口,那还是不要使用反射去获取了,避免以后官方实现发现了变化,那先前的反射也就会报错了),再将file置空让gc能够回收原来MultipartFile指向的内存,这样子没有拷贝多一份数据,大文件就不会多加一倍内存而溢出了。
 public ApiResult<UploadResult> storeFile( MultipartFile file) throws IOException {
       ...
        File tempFile = File.createTempFile("video", null);
        Log.info("临时文件目录:" + tempFile.getCanonicalPath());
        file.transferTo(tempFile);
        String originalName= URLEncoder.encode(file.getOriginalFilename(),"utf8");
        file=null;//file置为null是为了告诉gc此块内存可以回收
        RequestBody rb = RequestBody.create(MediaType.parse("multipart/form-data"), tempFile);
        MultipartBody.Part part = MultipartBody.Part.createFormData("file",originalName, rb);
        EFSService efsService = getRandEFSService();
        Response<ApiResult<UploadResult>> res = efsService.upload(part, module).execute();
       ...
  • 本人测试过程中发现上传文件有时会出现以下这个错误,重启后会消失,奇怪的是出现这个问题时下断点发现竟然都没执行到,不知在哪里就抛出了这个异常(原因暂时不详,可能是springboot上传文件用到了临时目录,而这个临时目录又很容易被系统删除)。
Failed to parse multipart servlet request; nested exception is java.io.IOException: The temporary upload location [C:\Users\HuWeiJian\AppData\Local\Temp\tomcat.4476717864971067098.8101\work\Tomcat\localhost\ROOT] is not valid

解决办法是通过

* 自定义临时文件目录,确保目录不会被系统删除导致抛异常 * @return @Bean public MultipartConfigElement multipartConfigElement(){ MultipartConfigFactory factory=new MultipartConfigFactory(); String location =System.getProperty("user.dir")+tempFileDir; Log.info("location="+location); File tmpDir=new File(location); if(!tmpDir.exists()){ tmpDir.mkdirs(); factory.setLocation(location); return factory.createMultipartConfig();
  • 或者在配置文件中增加:server.tomcat.basedir: /yourDir
  • 本人能力有限,如有错误请不吝指教。
  • MultipartFile其实只是一个接口,真正实现在org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.StandardMultipartFile,
  • StandardMultipartFile里面有个javax.servlet.http.Part对象,
  • Part也是一个接口,真正实现在org.apache.catalina.core.ApplicationPart,
  • ApplicationPart里有个org.apache.tomcat.util.http.fileupload.FileItem接口和File,
  • .FileItem实现是org.apache.tomcat.util.http.fileupload.disk.DiskFileItem,File表示上传的文件(是一个临时存放文件)
  • DiskFileItem是由org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory创建出来的,
  • 从DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD = 10240可以得知如果文件大小在10KB以内,则直接放在内存,如果大于10KB,则存储在本地磁盘中(注意是存在临时目录中,意味着这个文件如果你不持久化那这个文件随时会被系统清除)

Java中OutOfMemoryError(内存溢出)的三种情况及解决办法 - chen_lay的博客 - CSDN博客
https://blog.csdn.net/chen_lay/article/details/52209748
SpringBoot项目优化和Jvm调优(楼主亲测,真实有效) - 熊本同学 - CSDN博客
https://blog.csdn.net/wd2014610/article/details/82182617

springboot上传大文件时内存溢出的可能解决办法在springboot中上传大文件时要考虑内存的情况,一般我们会通过在执行服务时加入-Xms512m -Xmx512m等参数加大堆内存,但这是指标不治本的,关键还是看代码处理的时候有无导致内存泄漏的原因。例如:java -Xms512m -Xmx512m -jar rent_web-1.0.0.jar有时候我们会需要把上传的文件再调... 异常org.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.OutOfMemoryError: Java heap space 由异常可知,触发的... -Xmx1024m -Xms1024m -Xmn2g -Xss128k -Xmx1024m:设置JVM最大可用内存为1024M。 -Xms1024m:设置JVM促使内存为1024m。此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。 -Xmn2g:设置年轻代大小为2G。整个JVM内存大小=年轻代大小 + 年老代大小 + 持久代大小。持久代一般固定大小... package com.hljt.uav.utils; import com.google.gson.Gson; import com.qiniu.common.QiniuException; import com.qiniu.http.Response; import com.qiniu.storage.BucketManager; import com.qiniu.storag...
上传接口: @RequestMapping("uploadFile") public Boolean uploadFile(@RequestParam("file") MultipartFile file) { String rootPath = System.getProperty("user.dir"); String filePath = rootPath + "/files/test.mp4"; try { File new
记录一下生产环境上传文件 发生的一次内存溢出问题 管理平台在上传文件抛出错误 OOM异常(jvm 内存溢出,就是内存不够用了),除了上传文件以外,其它操作没有什么问题 经过排查发现,后端controller接口 使用了 MultipartFile.getBytes() 去拿到文件的字节数组,试想下如果上传2个g的视频,那么这个bytes数组得多大?需要占用多少内存?经常网上查找,找到了一个方法,通过拷贝流的方式来做 错误的上传方式 FileUtils.uploadFile(file.get
fileMultipartFile候会用到MockMultipartFile 当你导入spring-test依赖的候 会跟某些依赖冲突(暂未找到具体是哪个冲突) 解决方法 重写一个类去实现MultipartFile接口 直接用MockMultipartFile的源码 public class MultipartFileDto implements MultipartFile { private final String name; private String origi
1.问题概述 在生产环境中,大批量数据处理和并发数较多的情况下可能会出现stack溢出的情况,在排除常规的OOM因素之后,我们还需要在生产环境中进行场景复现以监控内存的使用情况,最后得出优化方案。 MAEMON:守护线程,当JVM中只有daemon线程虚拟机关闭。典型的守护线程如:gc线程 PRIORITY:线程优先级 2.技术及工具
项目开发中需要将file转化为MultipartFile,网上百度发现使用org.springframework.mock.web.MockMultipartFile可以 File file3 = new File(fileMap.get("file").toString()); FileInputStream in_file = new FileInputStream(file3);...
这里写自定义目录标题SpringBoot实现文件下载的几种方式比较基础版然后这里先引申出进阶版:主动关闭文件流。使用缓存流,边读边写 SpringBoot实现文件下载的几种方式比较 目前,网上一搜SpringBoot环境下载文件。有多种实现方式,大概率出来的会是基础版的,基础版的有几个坑,我这里分别将基础版以及基础版会出现的问题,从而引申各种解决方法。 话不多说,直接上源码: @RestController public class TestDownload { @Value("${gen.
Tomcat内存溢出问题通常可以通过以下几种方式来解决: 1. 调整JVM内存参数:可以通过修改Tomcat的启动脚本中的JAVA_OPTS参数来增加JVM内存。比如,可以增加-Xms和-Xmx参数来设置JVM的最小内存和最大内存,以及-XX:MaxPermSize参数来设置永久区内存大小。 2. 优化Web应用:可以通过对Web应用程序进行优化来减少内存使用。比如,可以尽量使用JSP标签库、避免使用会占用大量内存的大对象、避免使用过多的Session等。 3. 升级Tomcat版本:新版本的Tomcat可能会修复内存泄漏等问题,从而减少内存使用。 4. 使用内存分析工具:可以使用内存分析工具来检测内存泄漏问题。比如,可以使用Eclipse Memory Analyzer来分析内存,并找出内存泄漏的原因。 5. 增加服务器硬件配置:如果以上方法无法解决内存溢出问题,可以考虑增加服务器的硬件配置,比如增加内存、CPU等。
关于Context.startForegroundService() did not then call Service.startForeground()的解决办法 cheetah_qiufeng: 安卓9、安卓10、安卓11都会出现 ffmpeg4.x支持的编解码器等相关信息一览表 一把锄头: 询问作者,现在你还有ffmpeg4.2的文件么,包含bin、include、lib这些的 编译Android可用的libuv库 juice会blue: 最后成功了吗 妙用布局代码xml进行RecyclerView.ItemDecoration的绘制 实际使用过程中,在measure方法中view.layoutParams为null,在 View.MeasureSpec.EXACTLY测量模式下铺满屏幕,博主有遇到过吗? 登录双token方案 liuyachao110: 我有个疑问,如果攻击者截取到了access_token和refresh_token,一直刷新获取新的access_token和refresh_token,那不是可以无限调用了。
 
推荐文章