Я пытаюсь загрузить 69 930 файлов в основной текстовый редактор. Все идет гладко, и после того, как все они загружены, объем памяти составляет очень прохладные 130 МБ. Однако во время пикового времени загрузки он может достигать 900–1200 МБ.
Вся память ссылается на _ 1_. Это используется только для загрузки файла в объектную модель, затем он больше никогда не используется и байты могут быть очищены.
Очевидно, вся дополнительная память очищается сборщиком мусора вскоре после загрузки, поэтому утечек памяти нет. Однако кажется излишним использовать столько дополнительной памяти.
Что я пробовал:
- Проблема с памятью «решается» путем
System.gc()
вызова сразу после закрытияZipFile
. Это приводит к ~ 75% времени наблюдения за потоками, высокой загрузке ЦП и медленной загрузке. - Уменьшение количества потоков в пуле. Это снизило нагрузку (до 300 МБ), но привело к значительному увеличению времени загрузки.
- WeakReference
Что у меня есть на данный момент:
Я вызываю нагрузку через пул потоков с 4 потоками, каждый из которых выполняет относительно простую задачу:
// Source source = ...;
final InputStream input = source.open();
// read into object model
input.close();
Source
в данном случае - это ZipFileSource
, который выполняет все чтение:
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
public class ZipFileSource implements Source {
private final String file;
private final String name;
private volatile ZipFile zip;
public ZipFileSource(final String file, final String name) {
this.file = file;
this.name = name;
}
@Override
public InputStream open() throws IOException {
close();
final ZipFile zipFile = new ZipFile(file);
final ZipEntry entry = zipFile.getEntry(name);
final InputStream stream = new ZipFileSourceZipInputStream(zipFile.getInputStream(entry));
this.zip = zipFile;
return stream;
}
@Override
public void close() throws IOException {
if (zip != null) {
zip.close();
zip = null;
}
}
private class ZipFileSourceZipInputStream extends InputStream {
private final InputStream stream;
ZipFileSourceZipInputStream(final InputStream stream) {
this.stream = stream;
}
@Override
public int read() throws IOException {
return stream.read();
}
@Override
public void close() throws IOException {
ZipFileSource.this.close();
stream.close();
}
}
}
У меня мало идей. Я дошел до того, что либо использую собственный распаковщик zip, блокируя каждый n
запрос на выполнение System.gc()
вызова, либо просто отказываюсь и позволяю ему делать свое дело.
minor gc
илиfull gc
выполняется jvm 4 раза автоматически, чтобы очистить молодое поколение или старое поколение во время загрузки файла. Затем вы явно вызвалиfull gc
. Это не утечка памяти. Сборщик мусора повлияет на нормальное обслуживание программы Java, поэтому он откладывается до тех пор, пока это необходимо (до того, как закончится память). Вы можете добавить больше памяти и выделить ее процессу Java, если это действительно необходимо. - person user218867   schedule 29.03.2016static int
, оператор остатка иSystem.gc()
вызов. Честно говоря, просто для того, чтобы сделать процесс более плавным, а не для решения каких-либо проблем (например, утечек памяти). Так что, на мой взгляд, это изменение необходимо. - person Obicere   schedule 29.03.2016-Xmx
небольшое значение, компромисс в том, что gc будет вызываться чаще, это я полагаю, не годится для вашей службы. 2) Если вы хотите, чтобы программа выполнялась очень быстро, выделите больше памяти также через-Xmx
, чтобы gc вызывался реже, и запускайте n потоков параллельно, где n = количество ваших процессоров. - person user218867   schedule 29.03.2016