Опитвам се да заредя 69 930 файла в основен текстов редактор. Това върви гладко и след като всички са заредени, паметта остава на много готини 130MB. По време на пиковото време на зареждане обаче това може да достигне максимум 900MB - 1200MB.
Цялата памет препраща към Inflater#buf
поле. Това се използва само за зареждане на файла в обектния модел, след което никога повече не се използва и байтовете могат да бъдат изчистени.
Очевидно цялата допълнителна памет се изчиства от събирача на отпадъци скоро след зареждането - така че няма изтичане на памет. Въпреки това изглежда просто ненужно да се използва толкова много допълнителна памет.
Какво съм пробвал:
- Проблемът с паметта се „разрешава“ чрез извършване на
System.gc()
извикване веднага след затваряне наZipFile
. Това води до ~75% време за наблюдение на нишките, високо натоварване на процесора и бавно време на зареждане. - Намаляване на броя на пула от нишки. Това намали въздействието (до 300MB), но доведе до значително по-дълго време за зареждане.
- 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
изрично. Не е изтичане на памет. 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