Java IOException "Previše otvorenih datoteka"

1. Uvod

Uobičajena zamka pri radu s datotekama na Javi je mogućnost da ponestane dostupnih deskriptora datoteka.

U ovom ćemo uputstvu pogledati ovu situaciju i ponuditi dva načina za izbjegavanje ovog problema.

2. Kako JVM obrađuje datoteke

Iako JVM izvrsno radi izolirajući nas od operativnog sustava, na OS delegira operacije niske razine poput upravljanja datotekama.

To znači da će za svaku datoteku koju otvorimo u Java aplikaciji operativni sustav dodijeliti deskriptor datoteke kako bi datoteku povezao s našim Java procesom. Kad JVM završi s datotekom, otpušta deskriptor.

Sada, zaronimo kako možemo pokrenuti iznimku.

3. Propuštaju se deskriptori datoteka

Sjetimo se da za svaku referencu datoteke u našoj Java aplikaciji imamo odgovarajući deskriptor datoteke u OS-u. Ovaj će se deskriptor zatvoriti samo kada se odbaci referentna instanca datoteke. To će se dogoditi tijekom faze odvoza smeća.

Međutim, ako referenca ostane aktivna i otvori se sve više i više datoteka, tada će na kraju OS ostati bez deskriptora datoteka za dodjelu. U tom će trenutku proslijediti ovu situaciju JVM-u, što će rezultirati IOException biti bačen.

Ovu situaciju možemo reproducirati kratkim jediničnim testom:

@Test public void whenNotClosingResoures_thenIOExceptionShouldBeThrown () {try {for (int x = 0; x <1000000; x ++) {FileInputStream leakyHandle = new FileInputStream (tempFile); } fail ("Metoda je trebala zakazati"); } catch (IOException e) {assertTrue (e.getMessage (). containsIgnoreCase ("previše otvorenih datoteka")); } catch (Iznimka e) {fail ("Neočekivana iznimka"); }} 

U većini operativnih sustava, JVM proces će ostati bez deskriptora datoteka prije dovršenja petlje, što će pokrenuti IOException.

Pogledajmo kako možemo izbjeći ovo stanje pravilnim rukovanjem resursima.

4. Rukovanje resursima

Kao što smo već rekli, deskriptori datoteka se objavljuju JVM postupkom tijekom Skupljanja smeća.

Ali ako referencu datoteke nismo pravilno zatvorili, sakupljač može odlučiti da je tada ne uništi, ostavljajući deskriptor otvorenim i ograničavajući broj datoteka koje bismo mogli otvoriti.

Međutim, taj problem možemo lako ukloniti osiguravajući da ako otvorimo datoteku, osiguramo da je zatvorimo kad nam više ne treba.

4.1. Ručno objavljivanje referenci

Ručno objavljivanje referenci bio je uobičajeni način da se osigura pravilno upravljanje resursima prije JDK 8.

Ne samo da moramo eksplicitno zatvoriti bilo koju datoteku koju otvorimo, ali također osigurajte da to radimo čak i ako naš kod ne uspije i izbaci iznimke. To znači koristiti konačno ključna riječ:

@Test public void whenClosingResoures_thenIOExceptionShouldNotBeThrown () {try {for (int x = 0; x <1000000; x ++) {FileInputStream nonLeakyHandle = null; isprobajte {nonLeakyHandle = new FileInputStream (tempFile); } napokon {if (nonLeakyHandle! = null) {nonLeakyHandle.close (); }}}} catch (IOException e) {assertFalse (e.getMessage (). toLowerCase (). sadrži ("previše otvorenih datoteka")); fail ("Metoda ne bi trebala uspjeti"); } catch (Iznimka e) {fail ("Neočekivana iznimka"); }} 

Kao konačno blok se uvijek izvršava, daje nam priliku da pravilno zatvorimo referencu, ograničavajući time broj otvorenih deskriptora.

4.2. Koristeći pokušajte s resursima

JDK 7 donosi nam čišći način zbrinjavanja resursa. To je obično poznato kao pokušajte s resursima i omogućuje nam delegiranje raspolaganja resursima uključivanjem resursa u probati definicija:

@Test public void whenUsingTryWithResoures_thenIOExceptionShouldNotBeThrown () {try {for (int x = 0; x <1000000; x ++) {try (FileInputStream nonLeakyHandle = new FileInputStream (tempFile)) {} // napravi nešto s datotekom} }Ex ) {assertFalse (e.getMessage (). toLowerCase (). sadrži ("previše otvorenih datoteka")); fail ("Metoda ne bi trebala uspjeti"); } catch (Iznimka e) {fail ("Neočekivana iznimka"); }}

Evo, izjavili smo nonLeakyHandle unutar probati izjava. Zbog toga će nam Java zatvoriti izvor umjesto da ga trebamo koristiti konačno.

5. Zaključak

Kao što vidimo, neuspjeh u pravilnom zatvaranju otvorenih datoteka može nas dovesti do složene iznimke s posljedicama u cijelom našem programu. Pravilnim rukovanjem resursima možemo osigurati da se ovaj problem nikada neće pojaviti.

Kompletni izvorni kôd članka dostupan je na GitHubu.


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