I have a Java method that loads chunked audio data for a podcast. From what I can tell, 2 or 3 users can access an audio (generally about 40MB) in the podcast and then my app runs out of memory and crashes (java.lang.OutOfMemoryError: null). I am using Java with the Play Framework.
@With(MP3Headers.class)
public static Result getAudioByChunk(Integer audioId) {
try {
final Audio requestedAudio = Audio.findById.byId(audioId);
int songLength = Files.readAllBytes(Paths.get(requestedAudio.filePath)).length;
final int begin, end;
final boolean isRangeReq;
response().setHeader("Accept-Ranges", "bytes");
if (request().hasHeader("RANGE")) {
isRangeReq = true;
String[] range = request().getHeader("RANGE").split("=")[1].split("-");
begin = Integer.parseInt(range[0]);
if (range.length > 1) {
end = Integer.parseInt(range[1]);
} else {
end = songLength - 1;
}
response().setHeader("Content-Range", String.format("bytes %d-%d/%d", begin, end, songLength));
} else {
isRangeReq = false;
begin = 0;
end = songLength - 1;
}
Chunks<byte[]> chunks = new ByteChunks() {
public void onReady(Chunks.Out<byte[]> out) {
try {
if (isRangeReq) {
out.write(Arrays.copyOfRange(Files.readAllBytes(Paths.get(requestedAudio.filePath)), begin, end));
} else {
out.write(Files.readAllBytes(Paths.get(requestedAudio.filePath)));
}
} catch (IOException ioe) {
} finally {
out.close();
}
}
};
response().setHeader("Content-Length", (end - begin + 1) + "");
if (isRangeReq) {
return status(206, chunks);
} else {
return status(200, chunks);
}
} catch (Exception e) {
return ok();
}
}
I have already tried increasing my JVM memory (I only have a gigabyte of total memory to work with on the server). Out of desperation I have tried nullifying 'chunks' and calling the garbage collector in a finally block after the return statements.
I think I am missing a command to release the memory after the chunks have been written to the Result, what exactly am I missing?
If more details are needed please let me know.