Java IOException „Príliš veľa otvorených súborov“

1. Úvod

Častým úskalím pri práci so súbormi v Jave je možnosť vyčerpania dostupných deskriptorov súborov.

V tomto tutoriáli sa pozrieme na túto situáciu a ponúkneme dva spôsoby, ako sa vyhnúť tomuto problému.

2. Ako JVM narába so súbormi

Aj keď JVM robí vynikajúcu prácu, keď nás izoluje od operačného systému, na operačný systém deleguje operácie na nízkej úrovni, ako napríklad správu súborov.

To znamená, že pre každý súbor, ktorý otvoríme v aplikácii Java, operačný systém pridelí deskriptor súboru, ktorý ho prepojí s našim procesom Java. Akonáhle JVM skončí so súborom, uvoľní deskriptor.

Poďme sa teraz venovať tomu, ako môžeme spustiť výnimku.

3. Unikajúce deskriptory súborov

Pripomeňme, že pre každý odkaz na súbor v našej aplikácii Java máme v operačnom systéme zodpovedajúci deskriptor súboru. Tento deskriptor bude uzavretý, až keď bude odstránená inštancia referenčného súboru. Stane sa tak počas fázy Zber odpadu.

Ak však referencia zostane aktívna a bude sa otvárať čoraz viac súborov, nakoniec v systéme OS dôjde k prideleniu deskriptorov súborov. Potom postúpi túto situáciu JVM, ktorej výsledkom bude Výnimka IO byť vyhodený.

Túto situáciu môžeme reprodukovať krátkym testom jednotky:

@Test public void whenNotClosingResoures_thenIOExceptionShouldBeThrown () {try {for (int x = 0; x <1000000; x ++) {FileInputStream leakyHandle = new FileInputStream (tempFile); } zlyhať ("Metóda mala zlyhať"); } catch (IOException e) {assertTrue (e.getMessage (). containsIgnoreCase ("too many open files")); } catch (Výnimka e) {fail ("Neočakávaná výnimka"); }} 

Vo väčšine operačných systémov sa procesu JVM pred dokončením cyklu vyčerpajú deskriptory súborov, čím sa spustí Výnimka IO.

Pozrime sa, ako sa môžeme vyhnúť tejto podmienke pri správnom zaobchádzaní s prostriedkami.

4. Manipulácia so zdrojmi

Ako sme už povedali, deskriptory súborov sú uvoľňované procesom JVM počas Garbage Collection.

Ak by sme ale nezatvorili správne referenciu na svoje súbory, zberateľ sa môže rozhodnúť, že referenciu v tom čase nezničí, a nechá deskriptor otvorený a obmedzí počet súborov, ktoré by sme mohli otvoriť.

Tento problém však môžeme ľahko odstrániť zabezpečením toho, že ak otvoríme súbor, zaistíme jeho zatvorenie, keď už ho nepotrebujeme.

4.1. Ručné uvoľnenie referencií

Manuálne uvoľnenie referencií bolo bežným spôsobom na zabezpečenie správneho riadenia zdrojov pred JDK 8.

Nielenže musíme výslovne zavrieť akýkoľvek súbor, ktorý otvoríme, ale tiež sa uistite, že to urobíme, aj keď náš kód zlyhá a vyvolá výnimky. To znamená použitie konečne kľúčové slovo:

@Test public void whenClosingResoures_thenIOExceptionShouldNotBeThrown () {try {for (int x = 0; x <1000000; x ++) {FileInputStream nonLeakyHandle = null; try {nonLeakyHandle = new FileInputStream (tempFile); } konečne {if (nonLeakyHandle! = null) {nonLeakyHandle.close (); }}}} catch (IOException e) {assertFalse (e.getMessage (). toLowerCase (). contains ("too many open files")); zlyhať („Metóda nemala zlyhať“); } catch (Výnimka e) {fail ("Neočakávaná výnimka"); }} 

Ako konečne blok sa vždy vykoná, dáva nám šancu správne uzavrieť našu referenciu, a tým obmedziť počet otvorených deskriptorov.

4.2. Použitím vyskúšajte zdroje

JDK 7 nám prináša čistejší spôsob nakladania s prostriedkami. Je všeobecne známy ako vyskúšajte zdroje a umožňuje nám delegovať disponovanie so zdrojmi zahrnutím zdroja do skús definícia:

@Test public void whenUsing TryWithResoures_thenIOExceptionShouldNotBeThrown () {try {for (int x = 0; x <1000000; x ++) {try (FileInputStream nonLeakyHandle = new FileInputStream (tempFile)) {// do some with the file}}} catch (IOException ) {assertFalse (e.getMessage (). toLowerCase (). contains ("too many open files")); zlyhať („Metóda nemala zlyhať“); } catch (Výnimka e) {fail ("Neočakávaná výnimka"); }}

Tu sme deklarovali nonLeakyHandle vnútri skús vyhlásenie. Z tohto dôvodu pre nás Java uzavrie zdroj, namiesto toho, aby sme ho museli používať konečne.

5. Záver

Ako vidíme, nesprávne zatvorenie otvorených súborov nás môže viesť k zložitej výnimke s dôsledkami v celom našom programe. Pri správnom zaobchádzaní so zdrojmi môžeme zabezpečiť, že sa tento problém nikdy nevyskytne.

Kompletný zdrojový kód článku je k dispozícii na GitHub.


$config[zx-auto] not found$config[zx-overlay] not found