Nedávno jsme narazili na chybu „Too many open files“ v tomcatu běžícím na našem produkčním Linuxovém serveru.
Jak jistě všichni víte v Javě se o správu paměti stará GC. Ten spustí svoji činnost ve chvíli, kdy je spotřebována paměť a je potřeba další.
Při vytvoření FileInputStream se otevře soubor (a vytvoří tzv. file descriptor). K zavření souboru dojde až ve finalizeru tohoto objektu. Finalizer je ovšem volán až ve chvíli, kdy je objekt uvolnění pomocí GC.
Pokud máte pro program přiděleno hodně paměti, nemusí být GC spuštěno dostatečně často a vyčerpá se limit současně otevřených souborů pro JVM/proces. Záludností tohoto problému je, že se objeví zčista jasna třeba i po roce provozu.
Řešení problému existuje několik:
- explicitně volat metodu close() na FileInputStream a podobných objektech
- zvýšit limit současně otevřených souborů příkazem ulimit -n 4000 .
Pozn.: jádro 2.6.x má maximální zakompilovanou hodnotu 1 000 000. Případně je nutno zvýšit i celkový počet otevřených souborů v celém systému echo 512000 > /proc/sys/fs/file-max - docílit častější spouštění GC – třeba tak, že snížíte max heap size. Tato třetí varianta je ve většině případů nepoužitelná.
O limitech operačních systému na počet otevřených souborů se více dočtete v kapitole „Appendix A – Operating system limits“ v mé diplomové práci.