我需要从服务器下载潜在的大文件。为了避免潜在的OutOfMemoryExceptions,我想使用InputStreams来防止一次将整个文件放入内存。
我决定运行一个(粗略的)基准测试,以确定从以下SO回答中给出的方法是否会减少内存占用:
https://stackoverflow.com/a/38664475/2434579
使用这个例子,我编写了这段代码,看看在任何给定时间内使用了多少内存:
public void memoryTest(){
// 20MB file: "https://www.hq.nasa.gov/alsj/a17/A17_FlightPlan.pdf"
// Small file: "https://upload.wikimedia.org/wikipedia/en/7/7e/Patrick_Star.png"
RequestCallback requestCallback = request -> request.getHeaders()
.setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL));
ResponseExtractor<Void> responseExtractor = response -> {
try {
InputStream is = response.getBody();
OutputStream outstream = new OutputStream(){
@Override
public void write(int b) throws IOException {
}
};
int size = 32528; // This value is the buffer size I get when I get a buffer size from an oracle.sql.BLOB instance
byte[] buffer = new byte[size];
int length = -1;
System.out.println("Before writing - MB: " + (double) (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / (1024 * 1024) + " / " + Runtime.getRuntime().totalMemory() / (1024 * 1024));
while ((length = is.read(buffer)) != -1) {
outstream.write(buffer, 0, length);
}
System.out.println("After writing - MB: " + (double) (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / (1024 * 1024) + " / " + Runtime.getRuntime().totalMemory() / (1024 * 1024));
is.close();
outstream.close();
} catch(Exception e){
e.printStackTrace();
}
return null;
};
restTemplate.execute(URI.create("https://www.hq.nasa.gov/alsj/a17/A17_FlightPlan.pdf"), HttpMethod.GET, requestCallback, responseExtractor);
}
当我下载20 MB文件时,这就是我的println语句所说的:
Before writing - MB: 134.33865356445312 / 627
After writing - MB: 214.2599334716797 / 627
当我下载小文件(小于1 MB)时,这就是我的println语句所说的:
Before writing - MB: 126.80110931396484 / 627
After writing - MB: 128.01902770996094 / 627
我看到当我下载20MB文件时,内存使用量增加了大约80 MB。我下载较小的文件时使用率很低(2MB)。我知道流是最好的做法,但从这些数据来看,我并不完全相信这个解决方案最能解决我的问题。
我的问题如下: