2009-11-02 76 views
3

我有一个Web应用程序坐在那里,它是一个文件存储库。此Web应用程序提供Web服务,允许客户端搜索存储库并通过SOAP下载任何附件。通过Java中的Web服务下载大文件

目前我试图使用Spring-WS 1.5.8与MTOM发送附件到客户端,但我不断收到内存错误。我不相信这些错误与我的Tomcat 6实例有关,因为我的服务器有8GB的内存,并且我配置了Tomcat以使用4GB的内存。我在小至200MB的文件上收到这些错误。

我需要使用SOAP,尽管它可能不是最好的方法。我更喜欢Spring的解决方案,但如果这不可能,那么我可以接受其他想法。我读过,可以使用AxiomSoapMessageFactory将文件流式传输到服务器以用于上载,但不是相反。这是真的?我使用Java 6

这里是我把春天WS框架内得到的错误:在Java中

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

你可以发布一些你的代码?你的超时时间是多少? – 2009-11-02 19:33:34

+0

请注意,OutOfMemoryErros出现在*任意位置*,但在记忆拥抱真的不是必需的。如果您的其他应用程序运行的是泄漏内存,则可能最终会导致应用程序崩溃,因为它是链中的最后一个。 – mhaller 2009-11-03 01:23:36

回答

3

它可能与你的eden空间很小有关。伊甸园空间是分配新对象的堆中的一部分,并且一直存在于GC之后。伊甸园的空间不是很大。 (我没有默认值,但默认设置与1GB堆只有64MB)

您的文件可能会被加载到伊甸园空间。要么没有200 MB可用空间,要么将字节数组分配给较小的并且需要增长。数组在Java中的唯一方法是分配一个新的更大的数组并执行memcopy。这将会从100MB增长到200MB,显然需要300MB的整个eden堆空间。

您可以尝试设置-XX:NewSize=4196M,它将分配4GB伊甸园堆空间。

我不得不说,我不知道我的Tomcat运行在某种服务器模式下,它使用了不同的GC /堆策略。

您可以使用jvmstat 3.0中的visualgc(不是与Java 5和6捆绑在一起的发行版)来监视堆,以确定哪个堆空间已满。

你可能也想看看:Tuning Garbage Collection with the 5.0 Java[tm] Virtual Machine

如果解决这个问题,你仍然会面临业绩不佳的一个不可扩展的解决方案。你可能会用某种直接流媒体更好。为此,不应该很难实现一个简单的servlet。

2

SOAP/XML始终还真不少开销,需要大量的内存。在这个特定情况下,它试图在内存中分配一个(太大)byte [],而不是直接将流写入另一种OutputStream(除了ByteArrayOutputStream之外的任何其他类型)。

你是否认为只是忘记了SOAP接口的事情,并回到基础使用java.net.URLConnection和进一步建设呢?这样,您可以使用FileOutputStream将InputStream直接写入磁盘,这比将整个内容存储在内存中效率更高。

0

看起来您正在处理内存中的完整文件,而不是在发送给客户端时读取它。

如果你创建一个URL来解析实际发送的文件并将它留给它,你可以将它分离到web服务器吗?