java - 在 Java 中通过 Web 服务下载大文件

标签 java spring-ws

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

目前我尝试使用 Spring-WS 1.5.8 和 MTOM 将附件发送到客户端,但我总是遇到内存不足的错误。我不认为这些错误与我的 Tomcat 6 实例有关,因为我的服务器有 8GB 内存,我将 Tomcat 配置为使用其中的 4GB。我在小至 200MB 的文件上遇到这些错误。

我需要使用 SOAP,尽管它可能根本不是最好的方法。我更喜欢 Spring 中的解决方案,但如果那不可能,那么我愿意接受其他想法。我读到可以使用 AxiomSoapMessageFactory 将文件流式传输到服务器以进行上传,但反之则不行。这是真的?我正在使用 Java 6。

这是我在 Spring WS 框架中不断遇到的错误:

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)

最佳答案

这可能与您的伊甸园空间太小有关。 eden 空间是堆的一部分,新对象在这里分配并保留,直到它们在 GC 中幸存下来。 伊甸园空间不是很大。 (我没有默认值,但在 1GB 堆的默认设置下它只有 64MB)

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

您可以尝试设置 -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 应该不会太难。

关于java - 在 Java 中通过 Web 服务下载大文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1663162/

相关文章:

java - 稀疏矩阵存储器

web-services - 调用 Soap WS,结果出现 "Couldn' 在构造信封时获取 SAX 解析器”错误

java - Spring WS : Soap fault not identified as Fault

Spring 3 (SWS2) : difference between <context:component-scan> and <sws:annotation-driven>

java - 如何在 Spring-WS 中向响应负载添加附件?

java - 在 Spring-WS 中支持 SOAP 1.1 和 SOAP 1.2 消息

java - Firebase - (具有多个子节点用户唯一键的 DataSnapshot ) - 空对象引用

java - 从回调更新类字段

java - 首次启动时致命信号 6 (SIGABRT) 代码=-6

java - DataOutputStream 和 OutputStreamWriter 的区别 : String compatibility?