Java IOException “For mange åpne filer”

1. Introduksjon

En vanlig fallgruve når du arbeider med filer i Java er muligheten for å gå tom for tilgjengelige filbeskrivere.

I denne opplæringen tar vi en titt på denne situasjonen og tilbyr to måter å unngå dette problemet på.

2. Hvordan JVM håndterer filer

Selv om JVM gjør en utmerket jobb med å isolere oss fra operativsystemet, delegerer den operasjoner på lavt nivå som filhåndtering til operativsystemet.

Dette betyr at operativsystemet vil tildele en filbeskrivelse for hver fil vi åpner i et Java-program for å knytte filen til Java-prosessen. Når JVM er ferdig med filen, frigjør den deskriptoren.

La oss nå dykke inn i hvordan vi kan utløse unntaket.

3. Lekkende filbeskrivere

Husk at for hver filreferanse i Java-applikasjonen har vi en tilsvarende filbeskrivelse i operativsystemet. Denne beskrivelsen lukkes bare når filreferanseforekomsten blir kastet. Dette vil skje i løpet av søppelfasen.

Imidlertid, hvis referansen forblir aktiv og flere og flere filer åpnes, vil OS til slutt gå tom for filbeskrivelser for å tildele. På det tidspunktet vil den videresende denne situasjonen til JVM, som vil resultere i en IO Unntak blir kastet.

Vi kan gjengi denne situasjonen med en kort enhetstest:

@Test offentlig ugyldig nårNotClosingResoures_thenIOExceptionShouldBeThrown () {prøv {for (int x = 0; x <1000000; x ++) {FileInputStream leakyHandle = ny FileInputStream (tempFile); } fail ("Metoden burde ha mislyktes"); } fange (IOException e) {assertTrue (e.getMessage (). containIgnoreCase ("for mange åpne filer")); } fange (Unntak e) {fail ("Uventet unntak"); }} 

På de fleste operativsystemer vil JVM-prosessen gå tom for filbeskrivere før sløyfen fullføres, og derved utløse IO Unntak.

La oss se hvordan vi kan unngå denne tilstanden med riktig ressurshåndtering.

4. Håndtering av ressurser

Som vi sa tidligere, blir filbeskrivere utgitt av JVM-prosessen under søppelinnsamling.

Men hvis vi ikke lukket filreferansen riktig, kan samleren velge å ikke ødelegge referansen på det tidspunktet, la beskriveren være åpen og begrense antall filer vi kunne åpne.

Vi kan imidlertid enkelt fjerne dette problemet ved å sørge for at hvis vi åpner en fil, sørger vi for at vi lukker den når vi ikke lenger trenger den.

4.1. Manuelt frigjøre referanser

Manuell utgivelse av referanser var en vanlig måte å sikre riktig ressursadministrasjon før JDK 8.

Ikke bare gjøre det vi må eksplisitt lukke filen vi åpner, men sørg også for at vi gjør det selv om koden vår mislykkes og gir unntak. Dette betyr å bruke endelig nøkkelord:

@Test offentlig ugyldig nårClosingResoures_thenIOExceptionShouldNotBeThrown () {prøv {for (int x = 0; x <1000000; x ++) {FileInputStream nonLeakyHandle = null; prøv {nonLeakyHandle = ny FileInputStream (tempFile); } til slutt {if (nonLeakyHandle! = null) {nonLeakyHandle.close (); }}}} fangst (IOException e) {assertFalse (e.getMessage (). toLowerCase (). inneholder ("for mange åpne filer")); fail ("Method Should Not Have Failed"); } fange (Unntak e) {fail ("Uventet unntak"); }} 

Som den endelig Blokk utføres alltid, det gir oss sjansen til å lukke referansen riktig, og dermed begrense antall åpne beskrivere.

4.2. Ved hjelp av prøv-med-ressurser

JDK 7 gir oss en renere måte å utføre ressursavhending på. Det er kjent som prøv-med-ressurser og lar oss delegere avhending av ressurser ved å inkludere ressursen i prøve definisjon:

@Test offentlig ugyldig nårUsingTryWithResoures_thenIOExceptionShouldNotBeThrown () {try {for (int x = 0; x <1000000; x ++) {try (FileInputStream nonLeakyHandle = new FileInputStream (tempFile)) {// gjør noe med filen}}} fangst (IOExeption ) {assertFalse (e.getMessage (). toLowerCase (). inneholder ("for mange åpne filer")); fail ("Metoden burde ikke ha mislyktes"); } fange (Unntak e) {fail ("Uventet unntak"); }}

Her erklærte vi nonLeakyHandle inne i prøve uttalelse. På grunn av dette vil Java stenge ressursen for oss i stedet for at vi trenger å bruke endelig.

5. Konklusjon

Som vi kan se, kan manglende lukking av åpne filer føre oss til et komplekst unntak med forgreninger over hele programmet. Med riktig ressurshåndtering kan vi sikre at dette problemet aldri vil presentere seg.

Den komplette kildekoden for artikkelen er tilgjengelig på GitHub.


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