1. 程式人生 > >【java】手動釋放資源問題

【java】手動釋放資源問題

前言:

java語言中由於有垃圾回收機制,因此大大解放了程式設計師的工作量,不再需要擔心自己忘記釋放不用的記憶體而導致記憶體洩露這樣尷尬的事情了,當我們高呼gc萬歲的時候,還是會發現在很多場景需要我們做一些手動close,或recycler。下面就這個問題進行總結。

1.有gc為什麼還需要手動釋放資源?

1)gc只能釋放記憶體資源,而不能釋放與記憶體無關資源。
2)gc回收具有不確定性,你根本不知道它什麼時候會回收,而對於需要程式設計師手動回收的資源往往具有這樣的特點:資源開銷大,不用需要立即釋放;或者資源是系統唯一的,不釋放會導致別的程式也無法使用該資源。那對於具有這些特點的資源就必須保證不使用後能夠立即釋放出這部分資源,而不能把這件事情交給一個具有不確定性的gc來完成。
3)有人可能會說java IO流資源雖然不能被gc直接釋放,但可以利用finalizer機制來釋放非java資源,事實上java也確實在IO流的一些類中這麼做了,如下:

    /**
     * 該段程式碼摘自FileInputStream原始碼,jdk版本1.8
     */
    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(); } }

但是請注意,這僅僅是api程式設計師的嚴謹,防止由於我們這些程式設計師的大意忘記手動close資源,這依舊不是我們不手動呼叫close方法釋放資源的藉口。因為第一finalize的執行時機是在gc前,而gc具有時間不確定性,所以finalize執行時間也不具有確定性,對於需要及時回收的資源finalize無法保證及時。第二,finalize不是解構函式,jvm也根本就不能保證finalize一定會執行,那麼就更不能依賴finalizer機制釋放資源了。

2.需手動釋放的常見資源

1)java IO流資源
2)jdbc資源(Connection,PrepareStatement,ResultSet)
3)android中的bitmap資源

3.資源關閉順序問題

單個資源關閉往往沒什麼可說的,直接關閉即可,但在java很多類體系中往往存在依賴關係和資源裝飾關係,這個時候就有關閉先後問題,否則還會引發異常

1)先開後關原則(棧原則)

整個模型像棧一樣,先開的後關(先進後出)。這個原則很像生活中的一件事情,那就是使用燃氣灶。使用燃氣灶的時候我們都是先開氣閥,再開啟燃氣灶的開關,做完飯我們則先關閉燃氣灶開關,最後再關上氣閥。(電腦主機和顯示器的開關順序也滿足這個原則,開機先開顯示器後開主機,關機先關主機後關顯示器,別問我為什麼,問你們微機老師去)

jdbc資源的開關順序如下:

先開啟Connection資源,再開啟PrepareStatement資源,最後開啟ResultSet資源。使用完畢後先呼叫ResultSet的close方法,再呼叫PrepareStatement的close方法,最後呼叫Connection的close方法。

java IO流資源的開關順序如下:

我們一般先開啟一個輸入流進行讀取操作,然後將讀取的資料寫入輸出流中,關閉時按照上面的原則,則應該先關輸出流,然後關閉輸入流。但是,我們發現在java io流關閉操作中,即使順序反了也不會出現異常。因為我們關閉流的時機是在讀寫完成之後,並且輸出流和輸入流一般用一箇中間buff陣列做資料傳遞關聯,並不像jdbc中資源之間的強依賴關聯,所以即使關閉一個,另一個並不受影響。

2)由外到內原則(洋蔥原則,%>_<%)

如果資源存在包裝巢狀關係,則先關閉外層,後關閉內層的。

java io流中,處理流裝飾節點流,我們應該先關閉裝飾流,再關閉節點流。原則上是這樣,但是我們發現這樣反而會出現程式異常,因為java api上已經幫我們做了這樣的事情。就是在處理流的close方法中呼叫了節點流的close方法。因此對java io流資源,如果是處理流,我們只需要呼叫處理流的close方法即可

相關推薦

java手動釋放資源問題

前言: java語言中由於有垃圾回收機制,因此大大解放了程式設計師的工作量,不再需要擔心自己忘記釋放不用的記憶體而導致記憶體洩露這樣尷尬的事情了,當我們高呼gc萬歲的時候,還是會發現在很多場景需要我們做一些手動close,或recycler。下面就這個

Javamaven多專案資源共享

<resources> <resource> <!-- <directory>${project.parent.relativePath}/../../config</directory> --&g

javaitoo項目實戰之hibernate 懶載入優化性能

bsp xtra extra pda 程序 前端框架 外連接 獲取 轉換成 在做itoo 3.0 的時候,考評系統想要上線,就開始導入數據了,僅僅導入學生2萬條數據,可是導入的速度特別的慢。這個慢的原因是由於導入的時候進行了過多的IO操作。可是導入成功之後,

javaitoo項目實戰之hibernate 批量保存優化

新的 hibernate 缺點 try 實戰 lis 插入 entity man 在itoo中。基本上每一個系統都有一個導入功能,大量的數據填寫進入excel模板中。然後使用導入功能導入的數據庫中,這樣能夠大大的提高工作效率。那麽導入就涉及到了批量保存數據庫的

Java滾動數組動態規劃UVA - 11137 - Ingenuous Cubrency

得到 lose math scanner light clas details 狀態 ann 滾動數組優化自己畫一下就明白了。 http://blog.csdn.net/u014800748/article/details/45849217 解題思路:本題利用遞推關系解決。

javaTCP和UDP傳輸協議

有序 equal sig [] link 客戶端 數據傳輸 端口 sock TCP協議和UDP協議的比較 TCP的全稱是Transmission Control Protocol (傳輸控制協議) 傳輸控制協議,是一種面向連接的協議,類似打電話 在通信的整個過程中

javaswitch case支持的7種數據類型

包裝類 mac 打開 拆箱 創建 eval get trade ocs switch表達式後面的數據類型只能是byte,short,char,int四種整形類型,枚舉類型和java.lang.String類型(從java 7才允許),不能是boolean類型。 在網上看到

java淺析反射

cat trac catch pan print cep div dex 屬性 1,什麽反射 反射就是一種動態編程的技術,可以在運行階段動態的創建對象以及動態調用方法,具體由實參決定。 2,Class java.lang.Class類的實例代表應用程序的類和接口,該類

java異或"^"的特性

bsp 如果 ava code 整數 emp 進制 spa div 1,什麽是異或 異或是一種邏輯運算符,使用符號“^”表示,異或就是在對二進制進行操作的過程中,相同的取0,不同的取1。 2,證明a==a^b^b; 關於這個結論讀者肯定都知道

java:多線程面試題

編寫 cond func condition pri ide syn ack rri 經常面試的時候,讓寫各種亂七八糟的多線程面試題,收集了很多,有些還是挺好玩的。 1、編寫程序實現,子線程循環10次,接著主線程循環20次,接著再子線程循環10次,主線程循環20

JavaFlumeFlume-NG啟動過程源代碼分析(一)

code extends fix tar top 依據 oid article gif 從bin/flume 這個shell腳本能夠看到Flume的起始於org.apache.flume.node.Application類,這是flume的main函數所在。   m

java<Jsoup>獲取網頁中的圖片

util puts lec import http imp stat tin 畫的 要做Android課程設計了,做一個爬漫畫的東東練一下手 1 package asd; 2 3 import java.io.File; 4 import java.io.Fil

java簡介(一)

編碼 http ... 設計 適合 不能 高度 代碼格式 操作系統 應用:web後端開發、android-app開發、大數據應用開發 學習:java會過時,但程序設計的思想不會過時 特點:1、面向對象,跨平臺,語法比c++簡單     2、以字節碼的形式運行在虛擬機上   

java深入了解JAVA可變長度的參數

這一 args 必須 滿足 深入 itl 重載 編碼 創建 到J2SE 1.4為止,一直無法在Java程序裏定義實參個數可變的方法——因為Java要求實參(Arguments)和形參(Parameters)的數量和類型都必須逐一匹配,而形參的數目是在

JavaDateUtil(2)

繼承 ava sim pla bool private throw ons tar import java.sql.Timestamp; import java.text.ParseException; import java.text.SimpleDateFormat;

Java基本類型和引用類型(值傳遞)

適合 and span print pri right bre enc this 【關鍵詞】 【問題】 · 加深對基本類型和引用類型的理解; 【效果圖】 【分析】 參見最後的【參考資料】 【解決方式】 【代碼】 public

JavaSwing+IO流實現一個簡單的文件加密程序

als oncommand override fault 源文件 abs directory imp select EncrytService package com.my.service; import java.io.File; import java

Java一臺服務器配置多個Tomcat

shu 找到 通過 下載 ref connect 解決方案 .gz header 需求緣由 最近接收了一個新的工具業務:ipublish發布系統,剛接手這個業務的時候,發現每次發布新的代碼 需要到群裏告知大家,我要停服務幾分鐘,準備更新代碼啦。這尼瑪 哪個公司

JavaSwing+IO流實現一個簡單的文件加密程序(較完整版)

move 初始 baidu images 文件選擇器 while login 一個 ktr 留著參考 beans package com.my.bean; import java.io.Serializable; public class

Java接口開發中關於接受和發送json的相關範例

actual not span data private pla doby arr oms 接受json package com.suneee.scn.wms.web.rocketmq; import java.util.List; import net.sf.jso