好久没有更新博客了,最近项目也接近尾声了,今天记录一个case处理过程。
一、问题描述
1. 异常信息
java.lang.OutOfMemoryError: Java heap space java.io.ByteArrayOutputStream.<init>(Unknown Source) org.apache.commons.fileupload.DeferredFileOutputStream.<init>(DeferredFileOutputStream.java:131) org.apache.commons.fileupload.DefaultFileItem.getOutputStream(DefaultFileItem.java:558) org.apache.commons.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:406) org.apache.struts.upload.CommonsMultipartRequestHandler.handleRequest(CommonsMultipartRequestHandler.java:193) org.apache.struts.util.RequestUtils.populate(RequestUtils.java:443) org.apache.struts.action.RequestProcessor.processPopulate(RequestProcessor.java:804) org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:203) org.apache.struts.action.ActionServlet.process(ActionServlet.java:1196) org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:432) javax.servlet.http.HttpServlet.service(HttpServlet.java:637) com.xxxx.ui.framework.ActionServlet.service(ActionServlet.java:138) javax.servlet.http.HttpServlet.service(HttpServlet.java:717) com.xxxx.ui.framework.SessionFilter.doFilter(SessionFilter.java:89)
2. 问题重现过程
1) 页面上有一个文件导入功能,可以导入IP信息列表,用户可以通过">>"和“<<”按钮对导入的信息进行添加和删除。
2) 当从文件中导入5000条IP信息时,数据导入过程可以从正常完成,导入后的数据也能正常显示。
3) 当将导入的5000条数据全部删除时,抛出上述OutOfMemoryError异常。
二、问题分析
第一次QA发现这个问题时,我想当然以为这是由于导入的数据量太大,导致内存用尽,从而报出这个错误。因为之前版本也有这个问题,所以优先级比较低。直到最近项目接近尾声,经老板提醒,IP地址信息每个存储都小于128byte, 5000个IP地址信息总共也只有500k, 为什么会导致内存耗尽呢? 此事背后一定隐藏着一个天大的秘密!
三、分析过程
1) 通过VisualVM连接tomcat进程,观察内存使用情况。
通过几次测试,发现每次提交删除大量IP地址数据时,内存会突然增大,从而导致OutOfMemoryError,而过段时间,通过垃圾回收,内存会重新回收。
2)排查代码
我在代码中处理IP信息删除的Action里设置断点,却发现在到达这个断点之前,已经抛出OutOfMemoryError,从而排除由于代码中创建大量对象导致OutOfMemoryError的可能性。
3) 通过观察异常堆栈,初步推断: Struts在处理Multipart request时,调用fileupload组件。 fileupload组件在创建流的过程中,内存不足导致OutOfMemoryError异常。
通过查看jsp文件,发现提交的form定义如下:
<html:form action="/saveSMTPConn.action" enctype="multipart/form-data">
由此可见Struts调用fileupload来处理multipart request可能有问题。 在Apache官网查阅了issue列表,只找到一个类似的issue: STR-1857. 这个issue中提到fileupload模块本身有缺陷,但没有提及详细原因。所以决定从源码入手进行分析。
四、源码分析
从官网上下载了Struts1.2.7和fileupload1.0的源码,导入IDE中开始调试。
1) 找到Struts调用fileupload进行Multipart Request解析的代码:
public void handleRequest(HttpServletRequest request) throws ServletException { // Get the app config for the current request. ModuleConfig ac = (ModuleConfig) request.getAttribute( Globals.MODULE_KEY); // Create and configure a DIskFileUpload instance. DiskFileUpload upload = new DiskFileUpload(); // The following line is to support an "EncodingFilter" // see http://nagoya.apache.org/bugzilla/show_bug.cgi?id=23255 upload.setHeaderEncoding(request.getCharacterEncoding()); // Set the maximum size before a FileUploadException will be thrown. upload.setSizeMax(getSizeMax(ac)); // Set the maximum size that will be stored in memory. upload.setSizeThreshold((int) getSizeThreshold(ac)); // Set the the location for saving data on disk. upload.setRepositoryPath(getRepositoryPath(ac)); // Create the hash tables to be populated. elementsText = new Hashtable(); elementsFile = new Hashtable(); elementsAll = new Hashtable(); // Parse the request into file items. List items = null; try { items = upload.parseRequest(request); } catch (DiskFileUpload.SizeLimitExceededException e) { // Special handling for uploads that are too big. request.setAttribute( MultipartRequestHandler.ATTRIBUTE_MAX_LENGTH_EXCEEDED, Boolean.TRUE); return; } catch (FileUploadException e) { log.error("Failed to parse multipart request", e); throw new ServletException(e); } // Partition the items into form fields and files. Iterator iter = items.iterator(); while (iter.hasNext()) { FileItem item = (FileItem) iter.next(); if (item.isFormField()) { addTextParameter(request, item); } else { addFileParameter(item); } } }从上述代码可以看到,首先定义DiskFileUpload对象,接着给这个对象设定参数,然后upload.parseRequest(request)返回解析后的参数列表(FileItem List) ,最后将结果放入相应的集合中。可见Struts调用fileupload主要用于解析header中的parameter,供自己后续处理。
相关推荐
在Struts中,文件上传是一个常见的需求,它允许用户从客户端上传文件到服务器。Apache Commons FileUpload库是Struts实现文件上传功能的核心组件。 首先,`DiskFileUpload`类是Apache Commons FileUpload库的主要类...
MAT(Memory Analyzer Tool)是IBM提供的一款强大的Java内存分析工具,它专为解决此类问题而设计,帮助开发者深入理解内存消耗,有效地定位内存泄漏和性能瓶颈。 MAT的使用方法和功能详解: 1. **数据获取**:首先...
在使用Apache Ant构建Java项目时,可能会遇到一个常见的问题,即`OutOfMemoryError`。这个错误通常发生在编译大量Java源文件时,由于资源耗尽,JVM无法分配足够的内存来执行任务。`OutOfMemoryError`是Java运行时...
总结,junrar的`OutOfMemoryError`问题是由于内存管理不当造成的,解决之道在于采用更高效的内存使用策略,如流式处理和内存映射文件。通过理解和应用这些技术,开发者可以提高junrar的性能,避免在处理大文件时出现...
java虚拟机OutOfMemoryError:Java heap space堆dump文件,可以直接用来分析。
- **日志记录与分析**:开启详细的垃圾回收日志,通过分析日志了解垃圾回收的频率和效果,以及可能存在的问题。 #### 结论 `java.lang.OutOfMemoryError: Java heap space`错误通常是由于内存配置不当、代码设计不...
综上所述,"大文件分片合并上传 feign调用"是Java开发中解决大文件传输问题的一种有效方法,它结合了分片、Feign调用和文件合并技术,既提高了系统性能,又降低了内存消耗,确保了大文件传输的可靠性和效率。...
内存泄露是Java应用程序中常见的问题,它会导致程序性能下降,甚至最终引发`java/lang/OutOfMemoryError`。IBM HeapAnalyzer和Pattern Modeling and Analysis (PMA)是两种强大的工具,专门用于诊断和解决这类问题。 ...
在IT领域,尤其是在Java开发中,`OutOfMemoryError`是一个常见的问题,通常表明程序在运行过程中耗尽了分配给它的内存资源。这个问题在本案例中发生在网店系统的升级后,经过压力测试,系统突然崩溃,抛出了`...
- 描述提到了对这个问题的相关资料进行整理,这意味着该文档将提供如何识别、分析并解决此类问题的方法。 #### 详细解析 **异常出现的原因:** 1. **内存分配不足**:默认情况下,JVM启动时分配的堆内存可能不...
#### 一、问题分析 1. **异常含义**: - `java.lang.OutOfMemoryError: Java heap space`表示Java程序在运行过程中耗尽了所有可用的堆内存空间。 - 当程序创建新的对象或者分配内存时,如果无法在现有的堆内存中...
在Java开发过程中,我们经常会遇到`java.lang.OutOfMemoryError`(简称OOM)的问题。这个问题的发生主要是由于JVM内存不足或程序中存在内存泄漏所引起的。本文将深入探讨OOM产生的原因以及如何有效地解决这一问题。 ...
java.lang.OutOfMemoryError处理错误 java.lang.OutOfMemoryError是Java虚拟机(JVM)中的一种常见错误,...java.lang.OutOfMemoryError是Java虚拟机中的一种常见错误,解决这种错误需要根据实际情况进行分析和解决。
针对 Tomcat 出现 `java.lang.OutOfMemoryError: PermGen space` 和 `java.lang.OutOfMemoryError: Java heap space` 的问题,通过调整 JVM 的内存配置以及优化应用本身,可以有效避免内存溢出的发生。同时,对于...
【Java虚拟机内存溢出分析】:当遇到`java.lang.OutOfMemoryError: unable to create new native thread`错误时,这通常表示系统无法为新的Java线程分配足够的内存,即操作系统层面的资源耗尽,而非Java堆内存不足。...
解决“OutOfMemoryError: PermGen space”问题虽然过程可能比较痛苦,但是一旦找到正确的方法,问题就能得到解决。本文提供的解决方案包括调整PermGen space的大小、优化代码、使用JConsole监控内存等,希望能帮助...
Java中的`java.lang.OutOfMemoryError`是一种常见的运行时错误,通常表示应用程序在尝试分配内存时遇到了问题。根据提供的信息,这个错误主要涉及到两个方面:`PermGen space`和`Java heap`,并且与Tomcat服务器相关...
为了解决根本问题,我们需要让JVM在出现`OutOfMemoryError`时生成堆转储(Heap Dump)文件。通过添加`-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/error`,当错误发生时,JVM会将内存快照保存到指定...