Unity3d: 資源釋放時存儲空間不足引發的思考和遇到的問題


  手機游戲第一次啟動基本上都會做資源釋放的操作,這個時候需要考慮存儲空間是否足夠,但是Unity沒有自帶獲取設備存儲空間大小的

接口,需要調用本地方法分別去android或ios獲取,這樣挺麻煩的。而且資源釋放是耗時的,這個時候,如果其他應用在做后台下載,萬一
把空間占完了怎么辦呢。可能有人會想到釋放資源的時候每一次寫操作都獲取一次存儲空間的大小,這樣當然能解決問題,但是同時也極大的
延長了資源釋放的時間,畢竟每一次本地方法的調用還是比較耗時的。
    既然調用本地方法麻煩又耗時,那有沒有什么方法不用調用本地方法呢?
    首先,我嘗試了一下直接不做任何判斷,只加了一個try catch,看看空間滿了能不能捕獲到異常。當然第一件事是把手機給塞滿。嗯,我的安卓機還有8G的存儲空間,那我用程序創建幾個1G的空文件吧。
                int buffer = 1024 * 1024 * 1024;
                using (var tempStream = File.Create(tempPath))
                {
                    tempStream.SetLength(buffer);
                    tempStream.Flush();
                    tempStream.Close();
                }
  文件創建出來了,然后查看文件的大小確實是1GB。然后再去設置里面查看設備的剩余空間,還是8G。嗯?不對。我再創建8個文件,還是不對。
看來占位文件是不計大小的,雖然看起來有那么大。。。那么改一下生成方式,老老實實寫文件
                int buffer = 1024 * 1024 * 1024;
                using (var tempStream = File.Create(tempPath))
                {
                    tempStream.Write(new byte[buffer], 0, buffer);
                    //tempStream.SetLength(buffer);
                    tempStream.Flush();
                    tempStream.Close();
                }
  這次對了,雖然慢了點,但也比從外部拷貝文件到手機里快多了。既然方法對了那就多創建幾個文件,當創建到第9個文件時,catch到異常,提示的 "Disk full XXX"。看來完全可以通過try catch的方式來判斷磁盤空間是否夠用嘛。當然catch到的不一定都是Disk full的異常,也有可能是out of memory。但是總歸是釋放資源失敗了,要給玩家一個交代,那么統一提示為 “釋放資源失敗,可能磁盤空間滿了“,然后這個時候自動上報異常,去后台查看就好了(我是用的Bugly)。如果你給玩家提示一個什么 “釋放資源失敗,內存溢出了“,玩家反而是一臉懵逼。
    所以,完全可以用try catch來替換通過本地方法獲取磁盤存儲空間的方式。
    我把獲取本地方法的地方給去掉,加了一個try catch,然后運行游戲,釋放資源
                        xxxxxxxx
                        ....
                        try
                        {
                            fileName = Path.Combine(unRootPath, fileName);
                            fileName = fileName.Replace('\\', '/');
                            using (FileStream streamWriter = File.Create(fileName))
                            {
                                WriteFile(s, streamWriter);

                                streamWriter.Flush();
                                streamWriter.Close();
                            }
                            ++nWriteCount;
                        }
                        catch (Exception ex)
                        {
                            UpdateLog.ERROR_LOG(ex.Message);
                            return;
                        }
                        ....
                        xxxxxxx
        protected int _bufferSize = 1024;
        protected byte[] _buffer = new byte[1024];

        private void WriteFile(ZipInputStream zi, FileStream outFile)
        {
            int size = 0;
            while((size = zi.Read(_buffer, 0, _bufferSize)) > 0)
            {
                outFile.Write(_buffer, 0, size);
            }
        }
    等待資源釋放觸發catch,但是,恐怖的事情發生了。游戲閃退了,閃退了,閃退了。。。
我查了下log,catch信息是打印出來了,也是 Disk full,為啥游戲就閃退了?剛剛還寫了測試代碼用來創建大文件,都沒有閃退呀。反復比較了一下代碼,發現是bufferSize不一樣,一個1k,一個1G。是這個引起的?我把bufferSize改成2k,不行。4k, 不行,6k,還是不行。1MB,可以了~~~隱約記得socket底層的buffer貌似是8kb,難道寫文件操作內部也有個8kb的buffer。我把size改成10k,也沒閃退。看來還真有可能。
    反編譯System.IO.FileStream這個dll,還真有一個默認8kb的設置
 
 
    看到這個代碼,buffer大於8k和小於8k,底層寫文件走的邏輯是不同的,在if里面會拋出寫文件失敗的異常,else里面可能就會卡死。當然這也是推測,哪位大神知道原因的,麻煩告知一下。
    好了,把buffer設置為10k,一樣沒有閃退,完美觸發異常,彈出友好提示。
        protected int _bufferSize = 1024 * 10;
        protected byte[] _buffer = new byte[1024 * 10];
 
    總結:通過try catch來捕獲磁盤空間不足是可行的,但是需要寫文件的bufferSize大於8k, 太大沒必要,10k比較合適。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM