2015-06-30 5 views
13

Ich entwickle Form Submission Service mit Jersey 2.0. Das Formular enthält mehrere Text Felder und eine Datei Feld. Ich brauche Datei, Dateinamen, Datei Medientyp und Datei Inhaltstyp und speichern Sie sie in Objektspeicher zu extrahieren.Upload von Jersey-Servicedateien verursacht OutOfMemoryError

@Path("upload") 
@Consumes({MediaType.MULTIPART_FORM_DATA}) 
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) 
public class UploadService { 
    @POST 
    public BlobDo uploadFile(FormDataMultiPart uploadedBody) { 
     String accountSid = uploadedBody.getField("account-sid").getValue(); 
     String apiToken = uploadedBody.getField("api-token").getValue(); 
     String checksum = uploadedBody.getField("checksum").getValue(); 

     FormDataBodyPart bodyPart = uploadedBody.getField("file"); 
     MySwiftObject obj = new MySwiftObject(bodyPart.getValueAs(InputStream.class)); 
     obj.setName(bodyPart.getContentDisposition().getFileName()); 
     obj.setContentType(bodyPart.getMediaType().toString()); 
     obj.setContentDisposition(bodyPart.getContentDisposition().toString()); 
    ... 
} 

pom.xml

<jersey.version>2.17</jersey.version> 

<dependency> 
    <groupId>org.glassfish.jersey.containers</groupId> 
    <artifactId>jersey-container-servlet-core</artifactId> 
</dependency> 
<dependency> 
    <groupId>org.glassfish.jersey.media</groupId> 
    <artifactId>jersey-media-json-jackson</artifactId> 
</dependency> 
<dependency> 
    <groupId>org.glassfish.jersey.test-framework.providers</groupId> 
    <artifactId>jersey-test-framework-provider-inmemory</artifactId> 
</dependency> 
<dependency> 
    <groupId>org.glassfish.jersey.media</groupId> 
    <artifactId>jersey-media-multipart</artifactId> 
</dependency> 
<dependency> 
    <groupId>org.glassfish.jersey.core</groupId> 
    <artifactId>jersey-server</artifactId> 
</dependency> 
<dependency> 
    <groupId>org.glassfish.jersey.ext</groupId> 
    <artifactId>jersey-bean-validation</artifactId> 
</dependency> 

Formulareinreichung Anfrage

POST /nbs/v2/upload HTTP/1.1 
Host: 127.0.0.1:8080 
Cache-Control: no-cache 
Postman-Token: a4c1d4e9-5f71-2321-3870-e9cac0524f8d 
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryA2Z9pPMA7y3da8BG 

------WebKitFormBoundaryA2Z9pPMA7y3da8BG 
Content-Disposition: form-data; name="account-sid" 

Q45Ppm5ukvdqjTQ6eW0O5ztTXipwnjKQx1p6cf+fbCQ= 
------WebKitFormBoundaryA2Z9pPMA7y3da8BG 
Content-Disposition: form-data; name="api-token" 

6397cd691909fdc14cef67dbc1dc2dc3 
------WebKitFormBoundaryA2Z9pPMA7y3da8BG 
Content-Disposition: form-data; name="file"; filename="screen_4_100155.jpg" 
Content-Type: image/jpeg 

......Exif..MM.*.............................b...........j 
------WebKitFormBoundaryA2Z9pPMA7y3da8BG 
Content-Disposition: form-data; name="checksum" 

6a3381b1d16bded4a3dfc325a8bb800e 
------WebKitFormBoundaryA2Z9pPMA7y3da8BG 

JVM-Heap-Größe

-Xmx=1024mb 

Die

Problem

Beim Hochladen ~ 50MB Datei zwei temporäre Dateien mit ähnlichen MD5-Summen werden im Verzeichnis /tmp/tomcat7-tomcat7-tmp mit Namen erstellt FileBackedOutputStream7949386530699987086.tmp und MIME8234229766850016150.tmp

Bevor Upload abgeschlossen Server Ausnahme

 
javax.servlet.ServletException: org.glassfish.jersey.server.ContainerException: java.lang.OutOfMemoryError: Java heap space 
    org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:421) 
    org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:386) 
    org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:335) 
    org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:222) 

werfen und löscht die Datei mit dem Namen MIME8234229766850016150.tmp aber verlässt den anderen. Und gelöschte FileBackedOutputStream....tmp Dateien füllen den gesamten Speicherplatz auf der Festplatte.


Was ich tat

  1. erhöhen Heap-Speicher zu 7 GB, aber ~ 200 MB-Dateien können nicht hochgeladen werden.

  2. Job auf dem Server ausführen, um alte temporäre Dateien zu löschen.

  3. Erstellt Datei mit dem Namen jersey-multipart-config.properties und Inhalt

    jersey.config.multipart.bufferThreshold = -1

Die Datei MIME[random numbers].tmp wird nicht mehr erstellt, aber FileBackedOutputStream[random number].tmp hängt immer noch auf der Festplatte, es sei denn tomcat neu gestartet wird.


Frage

  1. Wie kann Jersey große Dateien verarbeiten (vielleicht 1 GB) ohne temporäre Dateien auf meiner Festplatte zu verlassen? Der beste Fall wäre, keine Festplatte zu verwenden und kleine Stücke durch den Speicher zu übertragen.

  2. Warum bekomme ich Heap-Überlauf, wenn Eingangsstrom mit Dateien gesichert wird?


Materialien Ich las

  • Die Erklärung schließt die ich bisher gefunden. read
  • Dieser Typ hat ein ähnliches Problem, aber auf der Client-Seite. read
  • Kann Lösung enthalten, konnte aber die Antwort nicht verstehen. read
  • Ziemlich nah an meinem Problem, aber kann es nicht ausarbeiten. read
  • pufferThreshold Idee wurde von hier übernommen. read

Antwort

3

Es scheint, dass Problem # 1 durch Zugabe von folgenden Zeilen in meinem web.xml unter dem <servlet> Tag gelöst wurde

<multipart-config> 
     <location>/tmp</location> 
     <max-file-size>1000000000</max-file-size> 
     <max-request-size>1500000000</max-request-size> 
     <file-size-threshold>0</file-size-threshold> 
</multipart-config> 

und entfernt jersey-multipart-config.properties Datei.

Jetzt kann ich Dateien hochladen, die über 200 MB sind. Es werden keine temporären Dateien mehr erstellt.

Aber ich kann Problem # 2 immer noch nicht erklären.

Verwandte Themen