Мне требуется загрузить много (может быть> 5000) относительно небольших (менее килобайт) файлов во встроенную систему, поэтому у меня не слишком много памяти.
Я написал этот код, он используется для загрузки каждого отдельного файла (например, только один)
final int BUFFER_LENGTH = 64 * 1024;
URL fileUrl = new URL("http://10.10.0.119:8080/files/a.txt");
File fileToSave = new File("/Users/me/foo/a.txt");
URLConnection connection = fileUrl.openConnection();
connection.setConnectTimeout(5000);
connection.setReadTimeout(5000);
InputStream us = connection.getInputStream(); // HOT SPOT (1)
try (BufferedInputStream bs = new BufferedInputStream(us, (int) Math.min(fileSize, 8192))) // HOT SPOT (2)
{
try (FileOutputStream fs = new FileOutputStream(fileToSave))
{
int c;
while ((c = bs.read(data, 0, BUFFER_LENGTH)) != -1)
fs.write(data, 0, c);
}
}
Также отметим, что
private static final int BUFFER_LENGTH = 64 * 1024;
private final byte data[] = new byte[BUFFER_LENGTH]
Распределяется один раз для экземпляра загрузчика, например один раз в жизни.
Итак, я заметил, что этот код использует относительно большой (> 200 МБ) объем памяти (но все это успешно освобождается GC), и я начал профилирование с использованием своего JProfiler. Что я заметил, так это то, что connection.getInputStream()
выделяет около 120 МБ в течение срока службы моей программы, а также выделяет BufferedInputStream
(что я оптимизировал, уменьшив его размер, поместив точный размер в конструктор потока).
Вот мои результаты профилирования. Я включил сбор информации об объектах GCed. Как вы можете заметить, двумя самыми тяжелыми горячими точками являются URLConnection.getInputStream()
и new BufferedInputStream()
, о которых я упоминал.
Как я могу уменьшить использование памяти при таких обстоятельствах? Может быть, есть и другие решения, такие как:
- Повторное использование таких потоков
- Явно указывая размер
- Используя несколько разных подходов
Большое спасибо.