久久六月-亚洲国产综合在线区尤物-国产精品xxxx18a99-久久人人爽人人爽人人爽-亚洲视频黄色-日韩精选-一级做a爰片久久毛片-一本一道久久久a久久久精品91-在线日韩中文-久久精品久久精品-国产午夜伦理片-av在线激情-国产精品人妻久久ai换脸-日本三级全黄少妇三2020-无遮挡免费高清羞羞视频-亚洲色大成网站www在线

當前位置:首頁 > 今日熱點 > 民生資訊 > 正文

IO流為什么必須手動關閉,不能像其他的對象坐等GC回收?

2023-07-07 09:32:43    來源:Java極客技術    
一、問題回溯

在項目的開發過程中,當我們對文件進行讀寫操作時,不知道大家有沒有碰到這樣的問題。

有的同學在做一個讀取臨時文件數據的工作,當讀完文件內容,準備將其刪除的時候,有時候會正常,但有時候會提示:操作無法完成,因為文件已在 Java? Platform SE binary 中打開,編譯器也會提示:Resource leak: "xxxx" is never closed。


(資料圖)

樣例代碼如下:

File file = new File("xxx.txt");// 實例化輸入流FileReader reader = new FileReader(file);// 緩沖區char[] buffer = new char[1024];// 分次讀取數據,每次最多讀取1024個字符,將數據讀取到緩沖區之中,同時返回讀取的字節個數int len;while ((len = reader.read(buffer)) > -1) {    // 字符轉為字符串    String msg = new String(buffer, 0, len);    System.out.println(msg);}// 刪除文件file.delete();

經過排查,發現出現該問題的原因是:讀取文件的 IO 流沒有正常的關閉,導致文件一直被流持有,刪除文件不成功!

那這么解決這個問題呢?答案其實也很簡單,當讀完 IO 流的數據或者寫完數據,手動調用一下關閉流的方法,最后再進行刪除文件。

// 刪除文件之前,先將 IO 流關閉reader.close();// 刪除文件file.delete();

可能有的同學會發出疑問,為什么 IO 流必須手動關閉,不能像其他的方法一樣坐等 GC 回收?

今天我們就一起來聊聊這個話題,以及如何正確的關閉 IO 流操作。

二、為什么 IO 流需要手動關閉?

熟悉編程語言的同學,可能知道,無論是 C 語言還是 C++,都需要手動釋放內存,但是 Java 不需要。

這主要得益于 Java 的虛擬機垃圾回收機制,它可以幫助開發者自動回收內存中的對象,不需要手動釋放內存,但是有些東西它是無法回收的,例如端口、顯存、文件等,超出了虛擬機能夠釋放資源的界限。

如果對未關閉流的文件進行讀寫操作,可能就會報錯,告訴你這個文件被某個進程占用。如果不手動釋放資源,隨著資源占有量逐漸增多,垃圾會越來越多,最終可能導致系統無法存儲其他的資源,甚至會出現系統崩潰。

一般來說,只要存在 IO 流讀寫操作,無論使用到的是網絡 IO 或者文件 IO,都是需要和計算機內的資源打交道的,清理計算機上面的垃圾,Java 的虛擬機垃圾回收機制沒有這個能力。

熟悉 Java 虛擬機垃圾回收機制的同學,可能知道 gc 有兩個顯著的特點:

gc 只能釋放內存資源,而不能釋放與內存無關的資源gc 回收具有不確定性,也就是說你根本不知道它什么時候會回收

所以進行流的操作時,凡是跨出虛擬機邊界的資源都要求程序員自己手動關閉資源。

可能有的同學又發出疑問,我平時本地測試的時候沒有發現這個問題,為什么部署到線上就出這個提示的呢?

以讀取文件的FileInputStream流為例,其實里面隱含了一個finalize方法,當虛擬機進行垃圾回收之前,會調用這個方法。

打開源碼,你會發現底層調用的其實是close釋放資源的方法,可以看到 JDK 間接的幫助開發者進行最后一次的兜底。

/** * Ensures that the close method of this file input stream is * called when there are no more references to it. * * @exception  IOException  if an I/O error occurs. * @see        java.io.FileInputStream#close() */protected void finalize() throws IOException {    if ((fd != null) &&  (fd != FileDescriptor.in)) {        /* if fd is shared, the references in FileDescriptor         * will ensure that finalizer is only called when         * safe to do so. All references using the fd have         * become unreachable. We can call close()         */        close();    }}

這就解釋了,為什么只是時不時的會出現提示,并不是總是。這個方法什么時候被調用,這取決于虛擬機的垃圾回收頻次。

但是在實際的開發過程中,開發者不能完全依賴虛擬機幫你回收這些系統資源,只要涉及到流的操作,強烈建議大家一定要手動關閉釋放資源,避免出現一些不必要的bug。

具體如何手動釋放資源資源呢,我們接著看!

三、正確的關閉流姿勢介紹

我們深知在操作 Java 流對象后要將流進行關閉,但是現實的情況卻往往不盡人意,原因是每個開發者的寫法可能不盡相同,不同的寫法導致出現各種千奇百怪的問題,下面我們一起來看看幾種關閉流的代碼案例!

寫法 1:在 try 中關流,而沒在 finally 中關流
try {    OutputStream out = new FileOutputStream("file");    // ...操作流代碼    out.close();} catch (Exception e) {    e.printStackTrace();}

當操作流代碼報錯的時候,這種寫法會導致流無法正常的關閉,因此不推薦采用!

正確的操作方式,應該在finally里面完成,實例代碼如下:

OutputStream out = null;try {    out = new FileOutputStream("file");    // ...操作流代碼} catch (Exception e) {    e.printStackTrace();} finally {    // 在 finally 中進行關閉,確保一定能被執行    try {        if (out != null) {            out.close();        }    } catch (Exception e) {        e.printStackTrace();    }}
寫法 2:在關閉多個流時,將其放在一個 try 中

在關閉多個流時,有的同學嫌棄麻煩,將其放在一個 try 中完成,實例代碼如下:

OutputStream out1 = null;OutputStream out2 = null;try {    out1 = new FileOutputStream("file");    out2 = new FileOutputStream("file");    // ...操作流代碼} catch (Exception e) {    e.printStackTrace();} finally {    try {        if (out1 != null) {            // 如果此處出現異常,則out2流沒有被關閉            out1.close();        }        if (out2 != null) {            out2.close();        }    } catch (Exception e) {        e.printStackTrace();    }}

這種寫法下,當out1.close出異常的時候,out2.close是不會被正常關閉的,因此不推薦采用!

正確的操作方式,應該是一個一個的close,別偷懶,實例代碼如下:

OutputStream out1 = null;OutputStream out2 = null;try {    out1 = new FileOutputStream("file");    out2 = new FileOutputStream("file");    // ...操作流代碼} catch (Exception e) {    e.printStackTrace();} finally {    try {        if (out1 != null) {            out1.close();        }    } catch (Exception e) {        e.printStackTrace();    }    try {        if (out2 != null) {            out2.close();        }    } catch (Exception e) {        e.printStackTrace();    }}
寫法 3:在循環中創建流,在循環外關閉

有的同學在循環操作多個文件時,在循環外關閉文件流,實例代碼如下:

OutputStream out = null;try {    for (int i = 0; i < 10; i++) {        out = new FileOutputStream("file");        // ...操作流代碼    }} catch (Exception e) {    e.printStackTrace();} finally {    try {        if (out != null) {            out.close();        }    } catch (Exception e) {        e.printStackTrace();    }}

表面看上去好像沒有問題,但是實際上創建了 10 個 IO 流,try 里面的邏輯執行完成之后,只是把最后的一個 IO 流對象賦予給了out參數。也就是當程序執行完畢之后,只關閉了最后一個 IO 流,其它 9 個 IO 流沒用被手動關閉,因此不推薦采用!

正確的操作方式,應該是在循環體內close,別偷懶,實例代碼如下:

for (int i = 0; i < 10; i++) {    OutputStream out = null;    try {        out = new FileOutputStream("file");        // ...操作流代碼    } catch (Exception e) {        e.printStackTrace();    } finally {        try {            if (out != null) {                out.close();            }        } catch (Exception e) {            e.printStackTrace();        }    }}
寫法 4:關閉多個流時,沒用遵循后定義先釋放原則

有的同學在操作多個文件流時,操作完成之后,依照先后次序進行關閉文件流,實例代碼如下:

FileOutputStream fos = null;BufferedOutputStream bos = null;try {    fos = new FileOutputStream("file");    bos = new BufferedOutputStream(fos);    // ...操作流代碼} catch (Exception e){} finally {    // 依次關閉流    try {        fos.close();    } catch (IOException e) {        e.printStackTrace();    }    try {        // 此處會報 java.io.IOException: Stream Closed 錯誤        bos.close();    } catch (IOException e) {        e.printStackTrace();    }}

按照先后順序關閉文件流,這種寫法下,有可能會報java.io.IOException: Stream Closed錯誤。

原因是BufferedOutputStream依賴于FileOutputStream,如果直接關閉FileOutputStream流,再次關閉BufferedOutputStream,會提示源頭已經被關閉,緩存區數據無法輸出。

正確的操作方式,應該遵循后定義先釋放的原則,實例代碼如下:

FileOutputStream fos = null;BufferedOutputStream bos = null;try {    fos = new FileOutputStream("file");    bos = new BufferedOutputStream(fos);    // ...操作流代碼} catch (Exception e){} finally {    // 后定義先釋放    try {        bos.close();    } catch (IOException e) {        e.printStackTrace();    }    try {        fos.close();    } catch (IOException e) {        e.printStackTrace();    }}
寫法 5:jdk7 及以上版本,推薦采用 try-with-resources 寫法

try-with-resources是 JDK 7 中引入的一個新的異常處理機制,它能讓開發人員不用顯式的釋放try-catch語句塊中使用的資源。

以上文為例,可以改成如下寫法:

try (FileOutputStream fos = new FileOutputStream("file");     BufferedOutputStream bos = new BufferedOutputStream(fos)){    // ...操作流代碼} catch (Exception e){    e.printStackTrace();}

try-with-resources釋放資源的操作,也是遵循的后定義先釋放的原則!

寫法 6:使用包裝流時,只需要關閉最后面的包裝流即可

包裝流是指通過裝飾設計模式實現的 IO 流類,其目的是對底層流的功能進行擴展,在實際數據傳輸的時候,還是使用底層流進行傳輸。比如緩存字節輸出流BufferedOutputStream就是一個包裝流,目的是對字節輸出流提供一個緩存區功能,讓數據輸出效率更高。

在使用到包裝流的時候,我們只需要關閉最后面的包裝流即可。

以上文為例,改寫的實例代碼如下:

InputStream is = null;InputStreamReader isr = null;BufferedReader br = null;try {    is = new FileInputStream("file");    isr = new InputStreamReader(is);    br = new BufferedReader(isr);    // ...操作流代碼} catch (Exception e){    e.printStackTrace();} finally {    // 關閉包裝流,也會自動關閉 InputStream 流    try {        br.close();    } catch (IOException e) {        e.printStackTrace();    }}

這是因為,包裝流關閉時會調用原生流的關閉方法,請看源碼!

public void close() throws IOException {    synchronized (lock) {        if (in == null)            return;        try {            // 這里的in 指的是 InputStreamReader,最后會原生流的close方法            in.close();        } finally {            in = null;            cb = null;        }    }}
四、內存流是否需要關閉?

在上文中,我們提到只要是 IO 流都建議大家手機關閉資源,但是在 Java 中有一種流,它是不需要手動關閉的,比如內存讀寫流:ByteArrayInputStream、ByteArrayOutputStream。

不同于指向硬盤的流,ByteArrayInputStream和ByteArrayOutputStream其實是偽裝成流的字節數組存儲在內存中(把它們當成字節數據來看就好了),他們不會鎖定任何文件句柄和端口,如果不再被使用,字節數組會被垃圾回收掉,所以不需要關閉。

當 IO 流是指向存儲卡 / 硬盤 / 網絡等外部資源的流,是一定要手動關閉的。

五、小結

本位主要圍繞【為什么 IO 流必須手動關閉,不能像其他的方法坐等 GC 處理】這個話題進行一次內容的整合和總結,同時也給出了推薦的正確關閉 IO 流的寫法。

在實際的開發過程中,建議大家正確的使用 IO 流,以免出現各種 bug !

內容難免有所遺漏,歡迎網友留言指出。

六、參考

1、csdn - 演員12138 - IO流為什么必須手動關閉,不能像其他的方法坐等GC處理

2、csdn - 思想永無止境 - Java之關閉流

關鍵詞:

上一篇:泉州市印發《關于加強孤獨癥兒童關愛服務的若干措施》
下一篇:最后一頁

久久六月-亚洲国产综合在线区尤物-国产精品xxxx18a99-久久人人爽人人爽人人爽-亚洲视频黄色-日韩精选-一级做a爰片久久毛片-一本一道久久久a久久久精品91-在线日韩中文-久久精品久久精品-国产午夜伦理片-av在线激情-国产精品人妻久久ai换脸-日本三级全黄少妇三2020-无遮挡免费高清羞羞视频-亚洲色大成网站www在线
  • 
    
    <rt id="iy8m0"><acronym id="iy8m0"></acronym></rt><nav id="iy8m0"><dl id="iy8m0"></dl></nav>
    <li id="iy8m0"></li>
    <rt id="iy8m0"></rt>
    
    
  • 国内外免费激情视频| www.av片| 男的插女的下面视频| 久久久久久久久久久99| 国精产品一区一区三区视频| 久草精品在线播放| av亚洲天堂网| 久久www视频| 欧美牲交a欧美牲交aⅴ免费真| 99视频在线视频| 女女同性女同一区二区三区按摩| 少妇一晚三次一区二区三区| 日韩免费一级视频| 亚洲免费成人在线视频| 黄色特一级视频| 精品国产成人av在线免| www.久久com| 女人和拘做爰正片视频| 午夜久久福利视频| 男人插女人视频在线观看| 九九九在线观看视频| 亚洲爆乳无码精品aaa片蜜桃| 国语对白做受xxxxx在线中国| 国产又粗又硬又长| 成人观看免费完整观看| 三级在线免费观看| 欧美黄色性生活| wwwwww欧美| 拔插拔插华人永久免费| xxxx18hd亚洲hd捆绑| 亚洲精品国产久| 精品免费国产一区二区| 免费人成自慰网站| 男生操女生视频在线观看| 成年人视频网站免费观看| 香蕉视频xxx| 日本男人操女人| 黄色大片中文字幕| 艳母动漫在线观看| 一道本在线免费视频| 国产三区在线视频| 免费人成自慰网站| 看全色黄大色大片| 激情黄色小视频| 亚洲免费一级视频| 国产第一页视频| 男人添女人下面高潮视频| 可以在线看黄的网站| 激情文学亚洲色图| 中文字幕永久视频| 成人精品视频一区二区| 国产v片免费观看| www.男人天堂网| 玖玖精品在线视频| aaaaaaaa毛片| 97超碰人人看| 亚洲一级片免费观看| 在线观看岛国av| 91极品视频在线观看| 性欧美极品xxxx欧美一区二区| 国产最新免费视频| 国产原创中文在线观看| 男女日批视频在线观看| 成人黄色片免费| 国产乱子伦精品无码专区| 99视频精品全部免费看| 日本福利视频在线观看| av磁力番号网| 偷拍盗摄高潮叫床对白清晰| 免费看啪啪网站| 经典三级在线视频| 国产一区二区三区播放| 国产精品69久久久| 91好吊色国产欧美日韩在线| 18禁网站免费无遮挡无码中文| 日本中文字幕网址| 久久久久狠狠高潮亚洲精品| 国产三级三级三级看三级| 99视频在线视频| 色婷婷激情视频| 成年丰满熟妇午夜免费视频| 妺妺窝人体色www看人体| 精品无码一区二区三区爱欲| 成人羞羞国产免费网站| 91亚洲精品久久久蜜桃借种| 免费成人进口网站| 国产精品专区在线| 日韩欧美黄色大片| aaaaaaaa毛片| 成人一区二区免费视频| 精品www久久久久奶水| 男人的天堂最新网址| 国产高潮呻吟久久久| 精品久久久久久无码中文野结衣| 大陆极品少妇内射aaaaa| 国产精品igao| 日韩不卡一二区| 3d动漫一区二区三区| 99久久激情视频| 亚洲 欧洲 日韩| 欧美视频在线播放一区| 一区二区三区视频在线观看免费| youjizz.com亚洲| 国产91在线免费| 不卡中文字幕在线观看| 精品一区二区三区无码视频| 青青在线视频观看| 看一级黄色录像| 无码日韩人妻精品久久蜜桃| 亚洲在线观看网站| 黄色一级视频片| 涩涩网站在线看| 精品国产一二三四区| 国产一级片自拍| www.日本在线播放| 天堂av.com| 亚洲一二三区av| 美脚丝袜脚交一区二区| www.cao超碰| 99蜜桃臀久久久欧美精品网站| 交换做爰国语对白| 国产成人久久777777| 精品人妻人人做人人爽| 天堂av8在线| 久久久久免费精品| 国产欧美日韩小视频| 亚洲综合激情视频| 日韩中文字幕二区| av网站手机在线观看| 男女h黄动漫啪啪无遮挡软件| 激情综合网俺也去| 91成人在线观看喷潮教学| 免费成人进口网站| 日韩视频在线观看一区二区三区| 久久无码高潮喷水| 91免费黄视频| 国产午夜精品视频一区二区三区| 色呦色呦色精品| 欧美在线观看视频网站| 北条麻妃在线视频观看| 免费人成在线观看视频播放| 日本黄色播放器| 捷克做爰xxxⅹ性视频| www.夜夜爽| 特级丰满少妇一级| 91激情视频在线| 成人性视频欧美一区二区三区| 99精品人妻少妇一区二区| 99久久免费观看| 免费在线看黄色片| 日韩黄色短视频| 人人妻人人澡人人爽欧美一区双| 男人添女人下部视频免费| 喜爱夜蒲2在线| 经典三级在线视频| 成人国产一区二区三区| 懂色av粉嫩av蜜臀av| 青青草原网站在线观看| 国产日韩欧美大片| 超级碰在线观看| 精品一区二区三区无码视频| 久久99久久久久久| 可以看毛片的网址| 99精品在线免费视频| 免费黄色福利视频| 成人黄色片视频| 超碰在线播放91| 奇米影音第四色| 欧美视频亚洲图片| 成人黄色片免费| 福利视频一二区| 国产一区亚洲二区三区| 成年人在线观看视频免费| 国产精品区在线| 熟女视频一区二区三区| www.avtt| 日本男人操女人| 中文字幕一区二区在线观看视频| 九九九久久久久久久| 男女啪啪免费观看| 国产特级黄色大片| 五月婷婷丁香色| 国产乱子伦精品视频| 国产成人a亚洲精v品无码| 玖玖爱视频在线| 毛片在线视频观看| 成人在线观看黄| 麻豆一区二区三区在线观看| 奇米精品一区二区三区| 黄大色黄女片18第一次| 天天做天天爱天天高潮| 国产免费成人在线| 欧美亚洲视频一区| 人人妻人人添人人爽欧美一区| 天天操狠狠操夜夜操| 国产精品88久久久久久妇女| 色综合av综合无码综合网站| 懂色av一区二区三区四区五区| aa视频在线播放| 色噜噜狠狠一区二区三区狼国成人|