我有一个web应用程序,它是一个文件存储库。此web应用程序提供web服务,允许客户端搜索存储库并通过soap下载任何附件。
目前,我已经尝试使用带mtom的springws 1.5.8将附件发送到客户机,但总是出现内存不足的错误。我不相信这些错误与我的tomcat6示例有关,因为我的服务器有8gb的内存,我将tomcat配置为使用4gb的内存。我在小到200mb的文件上得到了这些错误。
我需要使用soap,尽管它可能根本不是最好的方法。我更希望在Spring有一个解决方案,但如果那不可能,那么我愿意接受其他的想法。我了解到,可以使用axiomsoapmessagefactory将文件流式传输到服务器以进行上载,但不能反过来。这是真的吗?我正在使用Java6。
以下是我在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)
3条答案
按热度按时间rxztt3cl1#
看起来您正在处理内存中的完整文件,而不是在将其发送到客户端时读取它。
如果您创建一个解析为要发送的实际文件的url并将其保留给web服务器,那么您是否可以将其分流到web服务器?
db2dz4w82#
java中的soap/xml总是需要大量的开销和内存。在这种情况下,它试图在内存中分配一个(太大)字节[],而不是将流直接写入另一种输出流(bytearrayoutputstream除外)。
你有没有考虑过忘记soap接口的事情,回到使用java.net.urlconnection的基础上再进一步构建?通过这种方式,您可以使用fileoutputstream将inputstream直接写入磁盘,这比将整个内容存储在内存中要高效得多。
cuxqih213#
这可能与你的伊甸园空间太小有关。eden空间是堆的一部分,在那里新对象被分配并保留,直到它们在gc中幸存下来。伊甸园的空间不大(我没有默认值,但在1gb堆的默认设置中只有64mb)
你的文件可能会被载入伊甸园空间。要么没有200 mb的可用空间,要么字节数组被分配到较小的空间,需要增加。在java中,数组运行的唯一方法是分配一个新的更大的数组并执行memcopy。这将使从100mb增长到200mb显然需要300MB的eden堆空间。
你可以尝试设置
-XX:NewSize=4196M
它将分配4gb的eden堆空间。我不得不说,我不知道tomcat是在某种服务器模式下运行的,这种模式使用不同的gc/堆策略。
你可以用
visualgc
从jvmstat3.0(不是与java5和6捆绑在一起的发行版)监视堆并确定哪个堆空间已满。您可能还想看看:使用5.0java[tm]虚拟机调优垃圾回收
如果您解决了这个问题,您仍将面临性能低下和无法扩展的解决方案。你可能会更好地与某种形式的直接流。为此实现一个简单的servlet并不难。