Java IOException „Túl sok megnyitott fájl”

1. Bemutatkozás

A Java fájlokkal való munka során gyakori buktató a rendelkezésre álló fájlleírók elfogyásának lehetősége.

Ebben az oktatóanyagban megvizsgáljuk ezt a helyzetet, és két módot kínálunk a probléma elkerülésére.

2. Hogyan kezeli a JVM a fájlokat

Bár a JVM kiváló munkát végez az operációs rendszertől való elszigeteléssel, az operációs rendszert olyan alacsony szintű műveletekre ruházza át, mint a fájlkezelés.

Ez azt jelenti, hogy minden egyes Java alkalmazásban megnyitott fájlhoz az operációs rendszer egy fájlleírót rendel ki, amely a fájlt a Java folyamatunkhoz kapcsolja. Miután a JVM befejezte a fájlt, felszabadítja a leírót.

Most merüljünk el abban, hogy miként válthatjuk ki a kivételt.

3. Szivárgó fájlleírók

Emlékezzünk vissza arra, hogy a Java alkalmazás minden fájl hivatkozására az operációs rendszerben van egy megfelelő fájlleíró. Ez a leíró csak akkor lesz bezárva, ha a fájl hivatkozási példánya megsemmisül. Ez a Szemétgyűjtés szakaszában fog megtörténni.

Ha azonban a hivatkozás továbbra is aktív marad, és egyre több fájl van megnyitva, akkor az operációs rendszer végül kifog a fájlleírókból. Ezen a ponton továbbítja ezt a helyzetet a JVM-nek, ami egy IOException dobják.

Rövid egységvizsgálattal reprodukálhatjuk ezt a helyzetet:

@Test public void whenNotClosingResoures_thenIOExceptionShouldBeThrown () {try {for (int x = 0; x <1000000; x ++) {FileInputStream leakyHandle = új FileInputStream (tempFile); } fail ("A módszernek sikertelennek kellett lennie"); } catch (IOException e) {assertTrue (e.getMessage (). tartalmazIgnoreCase ("túl sok megnyitott fájl")); } catch (e kivétel) {fail ("Váratlan kivétel"); }} 

A legtöbb operációs rendszeren a JVM folyamatban a ciklus befejezése előtt elfogynak a fájlleírók, ezáltal elindítva a IOException.

Nézzük meg, hogyan kerülhetjük el ezt az állapotot az erőforrások megfelelő kezelésével.

4. Források kezelése

Mint korábban mondtuk, a fájlleírókat a JVM folyamat adja ki a Szemétgyűjtés során.

De ha nem zártuk be megfelelően a fájl referenciánkat, akkor a gyűjtő dönthet úgy, hogy akkor nem rombolja le a referenciát, nyitva hagyva a leírót és korlátozva a megnyitható fájlok számát.

Ezt a problémát azonban könnyen eltávolíthatjuk azzal, hogy megbizonyosodunk arról, hogy ha megnyitunk egy fájlt, akkor bezárjuk, ha már nincs rá szükségünk.

4.1. Hivatkozások kézi felszabadítása

A referenciák kézi kiadása a JDK 8 előtti általános erőforrás-kezelés biztosításának általános módja volt.

Nem csak kifejezetten be kell zárnunk a megnyitott fájlokat, de arról is gondoskodjon, hogy akkor is megtesszük, ha a kódunk meghiúsul, és kivételeket vet fel. Ez azt jelenti, hogy a végül kulcsszó:

@Test public void whenClosingResoures_thenIOExceptionShouldNotBeThrown () {try {for (int x = 0; x <1000000; x ++) {FileInputStream nonLeakyHandle = null; próbáld ki a {nonLeakyHandle = új FileInputStream (tempFile) fájlt; } végül {if (nonLeakyHandle! = null) {nonLeakyHandle.close (); }}}} catch (IOException e) {assertFalse (e.getMessage (). toLowerCase (). tartalmaz ("túl sok nyitott fájlt")); sikertelen ("A módszernek nem kellett volna kudarcot vallania"); } catch (e kivétel) {fail ("Váratlan kivétel"); }} 

Mivel a végül A blokk mindig végrehajtásra kerül, ez lehetőséget ad arra, hogy megfelelően lezárjuk referenciánkat, ezáltal korlátozzuk a nyitott leírók számát.

4.2. Használata erőforrásokkal próbálkozzon

A JDK 7 tisztább módot kínál számunkra az erőforrások ártalmatlanításának elvégzéséhez. Közismert nevén erőforrásokkal próbálkozzon és lehetővé teszi számunkra, hogy az erőforrások elidegenítését az erőforrásnak a próbáld ki meghatározás:

@Test public void whenUsingTryWithResoures_thenIOExceptionShouldNotBeThrown () {try {for (int x = 0; x <1000000; x ++) {try (FileInputStream nonLeakyHandle = new FileInputStream (tempFile)) {// csináljon valamit a fileExcepcióval ) {assertFalse (e.getMessage (). toLowerCase (). tartalmaz ("túl sok megnyitott fájlt")); sikertelen ("A módszernek nem kellett volna kudarcot vallania"); } catch (e kivétel) {fail ("Váratlan kivétel"); }}

Itt jelentettük ki nonLeakyHandle benne próbáld ki nyilatkozat. Emiatt a Java bezárja az erőforrást számunkra, ahelyett, hogy használnunk kellene végül.

5. Következtetés

Mint láthatjuk, a nyitott fájlok megfelelő bezárásának elmulasztása komplex kivételhez vezethet minket, programunk egészére kiterjedő következményekkel. Megfelelő erőforrás-kezeléssel biztosíthatjuk, hogy ez a probléma soha ne jelentkezzen.

A cikk teljes forráskódja elérhető a GitHub oldalon.


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