我有一个Web应用程序,它是一个文件存储库。此Web应用程序提供Web服务,允许客户端搜索存储库并通过SOAP下载任何附件。
目前我已经尝试使用带有MTOM的Spring-WS 1.5.8将附件发送到客户端,但我不断出现内存错误。我不相信这些错误与我的Tomcat 6实例有关,因为我的服务器有8GB内存,我配置Tomcat使用4GB。我在小到200MB的文件上收到这些错误。
我需要使用SOAP,尽管它可能根本不是最好的方法。我更喜欢Spring中的解决方案,但如果不可能,那么我对其他想法持开放态度。我读到可以使用AxiomSoapMessageFactory将文件流式传输到服务器以进行上载,但不是相反。这是真的?我使用的是Java 6。
以下是我在Spring WS Framework中遇到的错误:
java.lang.OutOfMemoryError: Java heap space
com.sun.xml.internal.messaging.saaj.util.ByteOutputStream.ensureCapacity(Unknown Source)
com.sun.xml.internal.messaging.saaj.util.ByteOutputStream.write(Unknown Source)
com.sun.xml.internal.messaging.saaj.packaging.mime.internet.BMMimeMultipart.find(Unknown Source)
com.sun.xml.internal.messaging.saaj.packaging.mime.internet.BMMimeMultipart.readBody(Unknown Source)
com.sun.xml.internal.messaging.saaj.packaging.mime.internet.BMMimeMultipart.getNextPart(Unknown Source)
com.sun.xml.internal.messaging.saaj.packaging.mime.internet.BMMimeMultipart.parse(Unknown Source)
com.sun.xml.internal.messaging.saaj.packaging.mime.internet.BMMimeMultipart.parse(Unknown Source)
com.sun.xml.internal.messaging.saaj.packaging.mime.internet.MimeMultipart.getCount(Unknown Source)
com.sun.xml.internal.messaging.saaj.soap.MessageImpl.initializeAllAttachments(Unknown Source)
com.sun.xml.internal.messaging.saaj.soap.MessageImpl.getAttachments(Unknown Source)
org.springframework.ws.soap.saaj.Saaj13Implementation.getAttachment(Saaj13Implementation.java:305)
org.springframework.ws.soap.saaj.SaajSoapMessage.getAttachment(SaajSoapMessage.java:226)
org.springframework.ws.support.MarshallingUtils$MimeMessageContainer.getAttachment(MarshallingUtils.java:109)
org.springframework.oxm.jaxb.Jaxb2Marshaller$Jaxb2AttachmentUnmarshaller.getAttachmentAsDataHandler(Jaxb2Marshaller.java:532)
com.sun.xml.internal.bind.v2.runtime.unmarshaller.MTOMDecorator.startElement(Unknown Source)
com.sun.xml.internal.bind.v2.runtime.unmarshaller.InterningXmlVisitor.startElement(Unknown Source)
com.sun.xml.internal.bind.v2.runtime.unmarshaller.SAXConnector.startElement(Unknown Source)
com.sun.xml.internal.bind.unmarshaller.DOMScanner.visit(Unknown Source)
com.sun.xml.internal.bind.unmarshaller.DOMScanner.visit(Unknown Source)
com.sun.xml.internal.bind.unmarshaller.DOMScanner.visit(Unknown Source)
com.sun.xml.internal.bind.unmarshaller.DOMScanner.visit(Unknown Source)
com.sun.xml.internal.bind.unmarshaller.DOMScanner.visit(Unknown Source)
com.sun.xml.internal.bind.unmarshaller.DOMScanner.visit(Unknown Source)
com.sun.xml.internal.bind.unmarshaller.DOMScanner.visit(Unknown Source)
com.sun.xml.internal.bind.unmarshaller.DOMScanner.scan(Unknown Source)
com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(Unknown Source)
com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(Unknown Source)
javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(Unknown Source)
org.springframework.oxm.jaxb.Jaxb2Marshaller.unmarshal(Jaxb2Marshaller.java:421)
org.springframework.ws.support.MarshallingUtils.unmarshal(MarshallingUtils.java:62)
org.springframework.ws.client.core.WebServiceTemplate$3.extractData(WebServiceTemplate.java:374)
org.springframework.ws.client.core.WebServiceTemplate.doSendAndReceive(WebServiceTemplate.java:560)
答案 0 :(得分:3)
它可能与您的伊甸园空间有关。 eden空间是堆的一部分,新对象被分配并保留,直到它们在GC中存活。 伊甸园空间不是很大。 (我没有默认值,但默认设置为1GB堆,它只有64MB)
您的文件可能会被加载到伊甸园空间中。要么没有200 MB可用空间,要么字节数组被分配为小而需要增长。数组在Java中的唯一方法是分配一个新的更大的数组并进行memcopy。这将从100MB增长到200MB显然需要300 MB的总eden堆空间。
您可以尝试设置-XX:NewSize=4196M
,它将分配4GB的eden堆空间。
我不得不说,我不知道我Tomcat是在某种服务器模式下运行的,它采用了不同的GC /堆策略。
您可以使用jvmstat 3.0中的visualgc
(不是与Java 5和6捆绑在一起的发行版)来监控堆,以确定哪个堆空间正在运行。
您也可以查看:Tuning Garbage Collection with the 5.0 Java[tm] Virtual Machine
如果您解决了这个问题,您仍将面临性能不佳的不可扩展的解决方案。使用某种直接流式传输可能会更好。它不应该是为此目的而难以实现一个简单的servlet。
答案 1 :(得分:2)
Java中的SOAP / XML总是有很多开销,需要大量内存。在这种特定情况下,它试图在内存中分配一个(太大)byte []而不是直接将流写入另一种OutputStream(除了ByteArrayOutputStream之外的任何东西)。
您是否考虑过忘记SOAP接口的事情并使用java.net.URLConnection回到基础并进一步构建?这样你就可以使用FileOutputStream将InputStream直接写入磁盘,这比将整个东西存储在内存中更有效。
答案 2 :(得分:0)
看起来你正在处理内存中的完整文件,而不是在发送到客户端时读取它。
如果您创建的URL解析为要发送的实际文件并将其保留给它,您是否可以将其分散到Web服务器?