Desidero formattare e scrivere il contenuto di un grande numero Map
(1.785.530 voci) in un file di testo. Dopo che circa l'85% delle voci è stato elaborato, diventa molto lento e quindi ricevo un OutOfMemoryException
.FileWriter memoria esaurita
Questo stesso errore si verifica, anche se io:
- chiamare periodicamente
flush()
oclose()
sul mioFileWriter
- uso
BufferedWriter
- scrivere ogni riga per un
StringBuffer
prima di scrivere il file
Questo è il mio codice:
private static final TreeMap<Date, Integer> accessesPerSecondMap = new
TreeMap<>();
...
private static void writeOutputFile() throws IOException {
FileWriter writer = new FileWriter(FILENAME_OUTPUT);
writer.write("Date");
writer.write(',');
writer.write("Request Count");
writer.write('\n');
for (Date date : accessesPerSecondMap.keySet()) {
// first and last date are not precise so do not write it in the
// file
if (date == accessesPerSecondMap.firstKey()
|| date == accessesPerSecondMap.lastKey()) {
continue;
}
writer.write(String.valueOf(date));
System.out.println("FileMerger wrote: " + String.valueOf(date));
writer.write(',');
writer.write(String.valueOf(accessesPerSecondMap.get(date)));
writer.write('\n');
}
writer.flush();
writer.close();
}
E qui è l'eccezione che viene generata:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at sun.util.resources.TimeZoneNames.getContents(Unknown Source)
at sun.util.resources.OpenListResourceBundle.loadLookup(Unknown Source)
at sun.util.resources.OpenListResourceBundle.loadLookupTablesIfNecessary(Unknown Source)
at sun.util.resources.OpenListResourceBundle.handleKeySet(Unknown Source)
at java.util.ResourceBundle.containsKey(Unknown Source)
at sun.util.locale.provider.LocaleResources.getTimeZoneNames(Unknown Source)
at sun.util.locale.provider.TimeZoneNameProviderImpl.getDisplayNameArray(Unknown Source)
at sun.util.locale.provider.TimeZoneNameProviderImpl.getDisplayName(Unknown Source)
at sun.util.locale.provider.TimeZoneNameUtility$TimeZoneNameGetter.getName(Unknown Source)
at sun.util.locale.provider.TimeZoneNameUtility$TimeZoneNameGetter.getObject(Unknown Source)
at sun.util.locale.provider.TimeZoneNameUtility$TimeZoneNameGetter.getObject(Unknown Source)
at sun.util.locale.provider.LocaleServiceProviderPool.getLocalizedObjectImpl(Unknown Source)
at sun.util.locale.provider.LocaleServiceProviderPool.getLocalizedObject(Unknown Source)
at sun.util.locale.provider.TimeZoneNameUtility.retrieveDisplayName(Unknown Source)
at java.util.TimeZone.getDisplayName(Unknown Source)
at java.util.Date.toString(Unknown Source)
at java.lang.String.valueOf(Unknown Source)
at FileMerger.writeOutputFile(FileMerger.java:95)
at FileMerger.main(FileMerger.java:26)
Aumentare lo spazio di heap funziona per me, ma non è una soluzione davvero soddisfacente a mio parere. Tra qualche giorno dovrò scrivere file due volte più grandi; spero che lo spazio sia abbastanza anche per loro.
Sto eseguendo Java 1.8.0_45 su Windows. Il codice sopra è il codice reale e l'unico codice in esecuzione. A scopo di verifica che uso il seguente codice per il riempimento del TreeMap
:
int accesses = 43267;
for (int i = 0; i < 1785530; i++) {
Date date = new Date(i);
accessesPerSecondMap.put(date, accesses);
}
ho aggiunto quanto segue al ciclo for per monitorare l'utilizzo della memoria:
...
int count = 100000;
for (Date date : accessesPerSecondMap.keySet()) {
if (count == 100000) {
count = 0;
printOutMemoryUsage();
}
count++;
...
private void printOutMemoryUsage() {
Runtime runtime = Runtime.getRuntime();
NumberFormat format = NumberFormat.getInstance();
StringBuilder sb = new StringBuilder();
long maxMemory = runtime.maxMemory();
long allocatedMemory = runtime.totalMemory();
long freeMemory = runtime.freeMemory();
sb.append("free memory: " + format.format(freeMemory/1024) + " ");
sb.append("allocated memory: " + format.format(allocatedMemory/1024)
+ " ");
sb.append("max memory: " + format.format(maxMemory/1024) + " ");
sb.append("total free memory: "
+ format.format((freeMemory + (maxMemory - allocatedMemory))/1024)
+ "<br/>");
System.out.println(sb);
}
sto ottenendo questa uscita quando non aumentare lo spazio di heap:
free memory: 28.868 allocated memory: 156.792 max memory: 253.440 total free memory: 125.516
free memory: 89.847 allocated memory: 253.440 max memory: 253.440 total free memory: 89.847
free memory: 87.796 allocated memory: 253.440 max memory: 253.440 total free memory: 87.796
free memory: 89.758 allocated memory: 253.440 max memory: 253.440 total free memory: 89.758
free memory: 32.478 allocated memory: 253.440 max memory: 253.440 total free memory: 32.478
free memory: 35.182 allocated memory: 253.440 max memory: 253.440 total free memory: 35.182
free memory: 37.269 allocated memory: 253.440 max memory: 253.440 total free memory: 37.269
free memory: 45.165 allocated memory: 253.440 max memory: 253.440 total free memory: 45.165
free memory: 42.943 allocated memory: 253.440 max memory: 253.440 total free memory: 42.943
free memory: 32.055 allocated memory: 253.440 max memory: 253.440 total free memory: 32.055
free memory: 13.053 allocated memory: 253.440 max memory: 253.440 total free memory: 13.053
free memory: 14.281 allocated memory: 253.440 max memory: 253.440 total free memory: 14.281
free memory: 12.797 allocated memory: 253.440 max memory: 253.440 total free memory: 12.797
free memory: 1.973 allocated memory: 253.440 max memory: 253.440 total free memory: 1.973
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
Con maggiore heapspace -Xms512m -Xmx1230m
ottengo:
free memory: 372.630 allocated memory: 506.816 max memory: 1.217.536 total free memory: 1.083.350
free memory: 329.031 allocated memory: 506.816 max memory: 1.217.536 total free memory: 1.039.751
free memory: 273.121 allocated memory: 506.816 max memory: 1.217.536 total free memory: 983.841
free memory: 333.700 allocated memory: 506.816 max memory: 1.217.536 total free memory: 1.044.420
free memory: 276.392 allocated memory: 506.816 max memory: 1.217.536 total free memory: 987.112
free memory: 220.482 allocated memory: 506.816 max memory: 1.217.536 total free memory: 931.202
free memory: 279.896 allocated memory: 506.816 max memory: 1.217.536 total free memory: 990.616
free memory: 223.986 allocated memory: 506.816 max memory: 1.217.536 total free memory: 934.706
free memory: 284.565 allocated memory: 506.816 max memory: 1.217.536 total free memory: 995.285
free memory: 228.654 allocated memory: 506.816 max memory: 1.217.536 total free memory: 939.374
free memory: 169.949 allocated memory: 506.816 max memory: 1.217.536 total free memory: 880.669
free memory: 230.528 allocated memory: 506.816 max memory: 1.217.536 total free memory: 941.248
free memory: 174.618 allocated memory: 506.816 max memory: 1.217.536 total free memory: 885.338
free memory: 235.197 allocated memory: 506.816 max memory: 1.217.536 total free memory: 945.917
free memory: 179.287 allocated memory: 506.816 max memory: 1.217.536 total free memory: 890.007
free memory: 123.376 allocated memory: 506.816 max memory: 1.217.536 total free memory: 834.096
free memory: 183.956 allocated memory: 506.816 max memory: 1.217.536 total free memory: 894.676
free memory: 128.046 allocated memory: 506.816 max memory: 1.217.536 total free memory: 838.766
FileMerger main method finished
È possibile aumentare molto lo spazio di heap da Eclipse molto facilmente –
Hai provato a lavare periodicamente? – Necreaux
Puoi provare a risolvere questo problema aumentando le dimensioni di heap predefinite di Java, ma potresti comunque ottenere questo errore. Quindi dovresti provare a implementare il tuo programma in modo tale da prevenire perdite di memoria e non generare OutOfMemoryError. – Bikku