2009-11-02 4 views
3

У меня есть веб-приложение, там, где есть хранилище файлов. Это веб-приложение предоставляет веб-службы, которые позволяют клиентам выполнять поиск в репозитории и загружать любые вложения через SOAP.Загрузка больших файлов через веб-службу в Java

В настоящее время я попытался использовать Spring-WS 1.5.8 с MTOM для отправки вложения клиенту, но у меня все время возникают ошибки памяти. Я не верю, что эти ошибки связаны с моим экземпляром Tomcat 6, потому что у моего сервера 8 ГБ памяти, и я настроил Tomcat на использование 4 ГБ. Я получаю эти ошибки в файлах размером до 200 МБ.

Мне нужно использовать SOAP, хотя это, вероятно, не самый лучший подход. Я бы предпочел решение весной, но если это невозможно, то я открыт для других идей. Я прочитал, что AxiomSoapMessageFactory можно использовать для потоковой передачи файлов на сервер для загрузки, но не наоборот. Это правда? Я использую Java 6.

Вот ошибка, которую я получаю в Spring Framework 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) 
+0

Можете ли вы опубликовать часть своего кода? На что рассчитаны ваши тайм-ауты? –

+0

Обратите внимание, что OutOfMemoryErros появляются * в любом месте *, но не обязательно, где обнимает память. если у вас есть другие приложения, на которых установлена ​​утечка памяти, вы можете в конечном итоге свернуть свое приложение только потому, что оно является последним в цепочке. – mhaller

ответ

3

Это могло бы иметь какое-то отношение к тому, чтобы пространство вашего пространства было маленьким. Эденское пространство является частью кучи, где новый объект распределяется и остается до тех пор, пока они не выжили GC. Эденское пространство не очень большое. (у меня нет значения по умолчанию, но при настройке по умолчанию с кучей 1 ГБ всего 64 МБ)

Ваш файл, вероятно, будет загружен в пространство эден. Либо нет свободного места на 200 МБ, либо массив байтов выделяется малым и должен расти. Единственный способ для массива, который бросается на Java, - это выделить новый массив и сделать memcopy. Это будет иметь рост от 100 МБ до 200 МБ, очевидно, требует 300 МБ общей площади кучи эденов.

Вы можете попробовать установить -XX:NewSize=4196M, который будет выделять пространство кучи 4 ГБ.

Должен сказать, что я не знаю, что Tomcat работает в каком-то режиме сервера, который использует разную стратегию GC/heap.

Вы можете использовать visualgc от jvmstat 3.0 (а не дистрибутив в комплекте с Java 5 и 6) для контроля кучи, чтобы определить, какое пустое пространство заполнено.

Вы также можете проверить: Tuning Garbage Collection with the 5.0 Java[tm] Virtual Machine

Если решить эту проблему, вы по-прежнему сталкиваются с низкой производительности в не масштабируемое решение. Вероятно, вам будет лучше с какой-то прямой потоковой передачей.Для этой цели не должно быть сложной реализации простого сервлета.

2

SOAP/XML в Java всегда очень много накладных расходов и требует много памяти. В этом конкретном случае он пытается выделить (слишком большой) байт [] в памяти вместо того, чтобы напрямую записывать поток в другой вид OutputStream (ничего, кроме ByteArrayOutputStream).

Вы считали, что просто забываете о интерфейсе интерфейса SOAP и возвращаетесь к основам, используя java.net.URLConnection и основываясь на этом дальше? Таким образом, вы можете написать InputStream непосредственно на диск с помощью FileOutputStream, который намного эффективнее, чем хранить все это в памяти.

0

Похоже, что вы обрабатываете полный файл в памяти вместо того, чтобы читать его, поскольку он отправляется клиенту.

Можете ли вы отклонить это на веб-сервере, если вы создали URL-адрес, который разрешает фактический файл для отправки и оставить его ему?