Это теория, но я не могу придумать каких-либо других причин, по которым ваш пример мог бы привести OOM.
Предположим, что несжатый файл состоит из очень длинной строки;например, что-то вроде 650 миллионов ASCII-байтов.
Кажется, ваше приложение просто читает файл по очереди за раз и (пытается) отображать текущее общее количество прочитанных мегабайт.
Внутри метод readLine()
читает символы по одному и добавляет их к StringBuffer
. (Вы можете увидеть вызов append
в трассировке стека.) Если файл состоит из очень большой строки, то StringBuffer
станет очень большим.
Каждыйтекстовый символ в несжатой строке становится char
в char[]
, который является буферной частью StringBuffer
.
Каждый раз, когда буфер заполняется, StringBuffer
будетувеличить буфер путем (я думаю) удвоения его размера. Это влечет за собой выделение нового char[]
и копирование в него символов.
Таким образом, если буфер заполняется при наличии N символов, Arrays.copyOf
выделит char[]
hold 2 xN символов. И в то время как данные копируются, в общей сложности будет использовано 3 x N символьного хранилища.
Таким образом, 650 МБ может легко превратиться в требование кучи> 6 x 650M байт
Следует также отметить, что массив 2 x N должен представлять собой один непрерывный узел кучи.
Глядя на графики кучи, похоже, что куча достигла ~ 1 ГБ. Если моя теория верна, следующее распределение было бы для узла ~ 2 ГБ. Но 1 ГБ + 2 ГБ прямо на пределе для вашей кучи 3.1 ГБ макс. И когда мы принимаем во внимание требование смежности, распределение не может быть выполнено.
Так, каково решение?
Это действительно просто: не используйте readLine()
, еслистроки могут быть неоправданно длинными.
public static String unzip(InputStream in)
throws IOException, CompressorException, ArchiveException {
System.out.println("Unzipping.............");
try (
GZIPInputStream gzis = new GZIPInputStream(in);
InputStreamReader reader = new InputStreamReader(gzis);
BufferedReader br = new BufferedReader(reader);
) {
int ch;
long i = 0;
while ((ch = br.read()) >= 0) {
i++;
if (i % (100 * 1024 * 1024) == 0) {
System.out.println(i / (1024 * 1024));
}
}
} catch (IOException e) {
e.printStackTrace();
LOG.error("Invoked AWSUtils getS3Content : json ", e);
}