2015-06-30 14 views
13

Tôi đang phát triển dịch vụ gửi biểu mẫu với Jersey 2.0. Biểu mẫu bao gồm một số trường văn bản và một trường tệp. Tôi cần trích xuất tệp, tên tệp, loại phương tiện tệploại nội dung tệp và lưu chúng trong cửa hàng đối tượng.Tải lên tệp dịch vụ Jersey khiến 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> 

yêu cầu nộp mẫu đơn

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 size

-Xmx=1024mb 

Các vấn đề

khi tải lên ~ 50MB tập hai tập tin tạm thời với số tiền MD5 tương tự được tạo ra trong thư mục /tmp/tomcat7-tomcat7-tmp với tên FileBackedOutputStream7949386530699987086.tmpMIME8234229766850016150.tmp

Trước khi upload xong máy chủ ném ngoại lệ

 
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) 

và xóa các tập tin với tên MIME8234229766850016150.tmp nhưng để lại cái còn lại. Và chưa xóa FileBackedOutputStream....tmp tệp lấp đầy toàn bộ dung lượng trên ổ đĩa cứng.


Những gì tôi đã làm

  1. gian Tăng heap để 7GB, nhưng ~ file 200MB không thể được tải lên.

  2. Chạy công việc trên máy chủ để xóa các tệp tạm thời cũ.

  3. tập tin tạo với tên jersey-multipart-config.properties và nội dung

    jersey.config.multipart.bufferThreshold = -1

File MIME[random numbers].tmp không còn được tạo ra, nhưng FileBackedOutputStream[random number].tmp vẫn treo trên ổ cứng trừ khi tomcat được khởi động lại.


Câu hỏi

  1. Làm thế nào Jersey có thể xử lý file lớn (có thể 1GB) mà không để lại các file tạm thời trên đĩa cứng của tôi? Trường hợp tốt nhất sẽ không được sử dụng ổ cứng và chuyển các phần nhỏ thông qua bộ nhớ.

  2. Tại sao tôi nhận được tràn heap nếu luồng đầu vào được sao lưu bằng tệp?


liệu tôi đọc

  • Các đóng lời giải thích tôi thấy cho đến nay. read
  • Anh chàng này có vấn đề tương tự nhưng ở phía khách hàng. read
  • Có thể chứa giải pháp, nhưng không thể hiểu câu trả lời. read
  • Khá gần với sự cố của tôi nhưng không thể giải quyết được. read
  • bufferThanh toán ý tưởng được lấy từ đây. read

Trả lời

3

Dường như vấn đề # 1 đã được giải quyết bằng cách thêm dòng sau trong web.xml của tôi dưới <servlet> thẻ

<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> 

và loại bỏ jersey-multipart-config.properties tập tin.

Bây giờ tôi có thể tải lên các tệp có dung lượng trên 200Mb. Không có tệp tạm thời nào được tạo.

Nhưng tôi vẫn không thể giải thích vấn đề # 2.

Các vấn đề liên quan