2009-11-02 7 views
3

Je dispose d'une application Web qui constitue un référentiel pour les fichiers. Cette application Web fournit des services Web qui permettent aux clients de rechercher dans le référentiel et de télécharger les pièces jointes via SOAP.Téléchargement de fichiers volumineux via le service Web en Java

Actuellement, j'ai essayé d'utiliser Spring-WS 1.5.8 avec MTOM pour envoyer la pièce jointe au client, mais je continue à manquer d'erreurs de mémoire. Je ne crois pas que ces erreurs sont liées à mon instance Tomcat 6 parce que mon serveur a 8 Go de mémoire et j'ai configuré Tomcat pour utiliser 4 Go de cela. Je reçois ces erreurs sur des fichiers aussi petits que 200 Mo.

J'ai besoin d'utiliser SOAP, même si ce n'est probablement pas la meilleure approche du tout. Je préférerais une solution au printemps, mais si ce n'est pas possible, je suis ouvert à d'autres idées. J'ai lu que l'on peut utiliser l'AxiomSoapMessageFactory pour diffuser des fichiers sur le serveur à des fins de téléchargement, mais pas l'inverse. Est-ce vrai? J'utilise Java 6.

Voici l'erreur que je continue à obtenir dans le cadre du printemps 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

Pouvez-vous poster une partie de votre code? À quoi correspondent vos délais d'expiration? –

+0

Veuillez noter que OutOfMemoryErros apparaît * n'importe où *, mais pas nécessaire là où le câlin de mémoire est vraiment. Si vous avez d'autres applications qui exécutent la mémoire de fuite, vous risquez de bloquer votre application simplement parce qu'elle est la dernière de la chaîne. – mhaller

Répondre

3

Cela pourrait avoir quelque chose à voir avec votre espace eden étant trop petit. L'espace eden est la partie du tas où les nouveaux objets sont alloués et restent jusqu'à ce qu'ils aient survécu à un GC. L'espace eden n'est pas très grand. (Je n'ai pas de valeur par défaut, mais sur la configuration par défaut avec 1 Go tas, il est seulement 64 Mo)

Votre fichier sera probablement chargé dans l'espace eden. Soit il n'y a pas 200 Mo d'espace libre, soit la matrice d'octets est allouée aux petits et a besoin de croître. La seule façon pour un tableau de hrow en Java est d'allouer un nouveau et plus grand tableau et de faire une memcopy. Ce sera la croissance de 100 Mo à 200 Mo nécessite évidemment 300 Mo d'espace de tas Eden total.

Vous pouvez essayer de définir -XX:NewSize=4196M qui allouera 4 Go d'espace de segment EDEN.

Je dois dire que je ne connais i Tomcat est en cours d'exécution dans certains mode serveur, qui utilise une stratégie diffrent GC/tas.

Vous pouvez utiliser visualgc à partir de jvmstat 3.0 (pas la distribution fournie avec Java 5 et 6) pour surveiller le tas et déterminer quel espace de tas est en cours d'exécution complète.

Vous pouvez également consulter: Tuning Garbage Collection with the 5.0 Java[tm] Virtual Machine

Si vous résoudre ce problème, vous serez toujours face à la mauvaise performance d'une solution évolutive non. Vous serez probablement mieux avec une sorte de streaming direct.Il ne devrait pas être difficile d'implémenter une simple servlet à cette fin.

2

SOAP/XML en Java a toujours vraiment beaucoup de frais généraux et a besoin de beaucoup de mémoire. Dans ce cas précis, il essaie d'allouer un octet (trop grand) en mémoire au lieu d'écrire le flux directement sur un autre type de OutputStream (tout sauf ByteArrayOutputStream).

Avez-vous pensé juste oublier la chose d'interface SOAP du tout et revenir à l'essentiel en utilisant java.net.URLConnection et de construire sur davantage? De cette façon, vous pouvez écrire le InputStream directement sur le disque en utilisant FileOutputStream, ce qui est bien plus efficace que de stocker tout le contenu en mémoire.

0

On dirait que vous manipulez le fichier complet en mémoire au lieu de le lire lorsqu'il est envoyé au client.

Pouvez-vous diverger sur le serveur web si vous créez une URL qui résout le fichier à envoyer et le laisse?