android開發:一例dv虛擬機器資源回收引起的有趣現象,附上一份可用的zip操作的工具類

來源:互聯網
上載者:User

自從進入android,接觸java以來,已與jvm及其gc機制有過多次“奇妙”接觸,jvm的gc實現有很多種,策略也不一樣,據我自己親身體會,即使是android手機的各個廠商的實現(當然,android上面的嚴格說來並不是jvm)甚至都不一樣,讓你遇到的話真是欲哭無淚。比如說涉及到softreference或者weakreference的時候,你發現程式的行為和文檔說明不一致的時候,請千萬不要驚奇。

 

話說android的文檔很多地方也不完善,比如說Bitmap,文檔上明明說一般不需要recycle,可是用過的同志應該明白,你敢不recycle嗎?(咱不較真兒啊。。。)當然,話題扯遠了,發個牢騷,這不,前兩天又遇到了一次問題。這個問題之前遇到過一次,百思不得其解,稀裡糊塗矇混過關了。這次再一次遇見,經過仔細觀察,認真思考,做實驗,查資料,好好糾結,終於尋得要領,並且經過了驗證。

 

假設有一個class名為PublicArea,另外有一個Class名為ZipUtil,前者主要用於資料交換,裡面有一些全域資料,後者提供了一個zip相關的static方法,用於從byte[]或者Inputstrem對象中提取需要的指定檔案名稱的檔案資料.

PublicArea類定義了兩個全域變數如下:

 

public static byte[] mZipdata=null; 
public static InputStream mZipIS=null;

 

ZipUtil類定義如下:

public class ZipUtil{

public static Map<String,byte[]> unzipFilesFromStream(InputStream is,String type) throws Exception
{
Map<String, byte[]> result = new HashMap<String, byte[]>();
ZipInputStream zipStream=new ZipInputStream(is);
ZipEntry zipEntry;
while((zipEntry=zipStream.getNextEntry())!=null){
if (zipEntry.getName().endsWith("."+type))
{
int zipsize=(int)zipEntry.getSize();
byte[] temp=new byte[zipsize];
byte[] beRead=new byte[zipsize];
int nowpos=0;
int beReadThisTime=0;
while(-1!=(beReadThisTime=zipStream.read(temp)))
{
System.arraycopy(temp,0,beRead,nowpos,beReadThisTime);
nowpos+=beReadThisTime;
temp=new byte[zipsize];
}
result.put(zipEntry.getName(), beRead);
}
zipStream.closeEntry();
}
zipStream.close();
return result;
}


public static byte[] unzipFileFromStream(InputStream is,String filename) throws Exception
{
byte[] result =null;
ZipInputStream zipStream=new ZipInputStream(is);
ZipEntry zipEntry;
while((zipEntry=zipStream.getNextEntry())!=null){
if (zipEntry.getName().equals(filename))
{
int zipsize=(int)zipEntry.getSize();
byte[] temp=new byte[zipsize];
byte[] beRead=new byte[zipsize];
int nowpos=0;
int beReadThisTime=0;
while(-1!=(beReadThisTime=zipStream.read(temp)))
{
System.arraycopy(temp,0,beRead,nowpos,beReadThisTime);
nowpos+=beReadThisTime;
temp=new byte[zipsize];
}
result=beRead;
}
zipStream.closeEntry();
}
zipStream.close();
return result;
}

}

 

我在PublicArea中通過一系列動作擷取了一份zip檔案的位元據(比如file讀取或者從網路傳輸)並將對象引用交給mZipdata,然後使用如下代碼:

mZipIS = new ByteArrayInputStream(mZipdata);

建立位元組流並將引用賦值給mZipIS 。

至此,mZipdata與mZipIS已建立相應對象,同時因為二者均為全域變數,所以除非我手動放棄引用,否則這兩個對象將一直存活。

ZipUtil中的兩個方法分別為:

public static byte[] unzipFileFromStream(InputStream is,String filename) 

public static Map<String,byte[]> unzipFilesFromStream(InputStream is,String type)

前者根據給定的InputStream擷取zip包中名為filename的檔案的二進位字對象。

後者是遍曆zip包中的檔案並將尾碼名為type的檔案的二進位位元組對象存入一個HashMap中,key為檔案名稱。

在這裡說一下,zip用來做遍曆速度很快,它的結構適合提取檔案名稱。

 

問題來了,我需要分別使用ZipUtil中的這兩個方法,先使用unzipFileFromStream,再使用unzipFilesFromStream,InputStream 參數當然就是PublicArea中的mZipIS了。但是在第二次調用ZipUtil的方法的時候,會爆出“NullPointerException”,著實蛋疼。mZipIS的對象是在第一次調用unzipFileFromStream的時候建立的,然後方法跑完,其他線程過一會兒會來調用unzipFilesFromStream方法,仍然想當然地使用這個mZipIS作為參數,然後就可恥地異常。ZipUtil被回收了。其實在開始的時候我還刻意沒有去在ZipUtil的實現中調用zipStream.close(); 這樣表面上看應該不會存在這樣的問題啊,那麼這個問題是怎樣產生的呢?這就要從多個方面說起了。

 

首先我們要複習一下java的io類的一個小特點,java的io類實現堪稱經典,所有的流式類的實現分為節點流和過濾流兩種,用了一種“裝飾設計模式”,一環套一環,形成一種鏈式結構。這裡要說一下它的資源釋放,當你將各種過濾流串起來之後,關閉的時候,你只需要對最後一個過濾流(就是串的尾端末梢)的引用調用close()方法即可釋放整個鏈式結構裡的流對象。

 

 

而我遇到的問題是因為在ZipUtil的方法實現中,在mZipIS尾端又加入了一個ZipInputStream過濾流,而它是局部變數,所以。。。方法執行完它就被華麗麗地釋放了,不光它被釋放,整個鏈式結構都被釋放,連累到了mZipIS。雖然mZipIS的引用仍然存在,但是dv虛擬機器的gc依然將它回收了,一方面dv虛擬機器的gc策略是盡量回收,另一方面我們也要認識到,gc的智能畢竟是有限的,同時程式員良好的編碼習慣很重要,肯定不存在完美的jvm和gc,不要將自動回收的機制摻和到太過於複雜的程式流程,否則真的是自討苦吃,對於簡單的程式流程來說,大部分的jvm的gc行為應該基本一致,因為沒什麼好選擇的,所以相對安全。雖然我們可以把很多問題怪罪於jvm和他gc不夠完善,但是。。。你能和機器較什麼勁兒呢 - -#

 

 

這裡我們也看到,對於mZipdata這種全域資料儲存的引用的使用,在哪裡產生流就在哪裡結束,不要依賴於一個流對象幻想用個千八百遍,你組合的一連串的面向需求的鏈式結構用完了就整體銷毀掉,養成良好的習慣,你自己手工銷毀那你自然該知道在用的時候建立。至於對資料引用的保持,還是使用byte[]引用吧,用的時候建立流,這樣條理清晰,也不麻煩,不能太懶啊。當然了,極端情況你看著辦吧,比如神馬網路不順暢並且沒有儲存空間並且記憶體不夠。。。。那就讓程式自殺好了(開玩笑的),跑題了,哈哈。

 

對了,那個zip工具類可以直接拿去用哦,有問題歡迎探討指教。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.