iOS 【你的項目內存溢出了嗎?】

在 App 的開發中,內存溢出、野指針滿天飛是很常見的現象。合理的規避內存溢出風險是我們需要做得。常見的,如數組越界,可造成程序的閃退崩潰。但一般這種類型的內存泄露比較容易定位,也容易解決。最近項目中遇到了一些很奇怪的現象,我拿來分享一下。


在我們的 App 中,會打包行車的軌跡點並上傳到後臺,並根據軌跡進行里程數統計和計費。但是最近一段時間經常有用戶反饋公里數異常爲 0,費用也不統計了。更奇怪的是這種現象時有時無,由於很難定位到錯誤發生的地方,所以比較難解決。於是我查看了服務器數據庫中我們上傳的數據包,發現出現公里數不計算的情況時數據包都被後臺拒收了。拒收的原因我們在錯誤日誌中也拿到了,那就是時間異常。正常來說,我們是以毫秒數統計的當前時間和服務器時間進行上傳,後臺解析出來正確的時間,但是錯誤日誌中顯示我們上傳的是 1969 年的某一天的時間,而且時間隨機沒有規律。於是徹底檢查了一下代碼。


在過程中,我發現我拿到的時間是沒有問題的,但上傳上去的時間有問題。錯誤出在了類型轉化上。如下錯誤代碼:

// 客戶端時間(毫秒數)
long localTime = (long long)[[[NSDate alloc] init] timeIntervalSince1970] * 1000;


本地時間使用了 longLongValue 進行轉化(毫秒長度比較長,使用 long 或者 int 長度不夠。long、int 爲 4 字節,而 long long 則是 8 字節。),但是卻用了 long 的指針進行接收。這樣一來就出現了一塊沒有指針指向的殭屍內存。爲什麼這麼說呢,先看一下下面兩篇文章:

OC 基本數據類型取值範圍以及字節數

C/C++ 基本數據類型所佔字節數


我們發現基本數據類型 OC 是繼承於 C 的,long 在 16 位、32 位編譯器下所佔 4 個字節、在 64 位編譯器下佔 8 個字節。而 long long 在 16 位、32 位、64 位編譯器下均佔 8 個字節。那麼我們用 long 型的指針去接收 long long 類型的數據,在 16 位、32 位的編譯環境下就會出問題。我們知道,指針可以指向該內存空間並且持有該內存空間,什麼意思呢?一旦一塊內存空間被指針所指向,那麼就可以通過這個指針去操作這塊內存空間使用,如果該指針還持有了該內存空間,那麼該內存空間就無法被其他的指針來訪問。


回到問題中來,我們用 long 型指針去接收 long long 類型的數據,那麼這個數據所在的內存空間只有 4 位被 long 型指針所持有,剩下的 4 位內存空間是沒有被持有的,那麼當手機內存剩餘量不足、進程過多的情況下,系統就會拿到這部分沒有被持有的內存分配給其他的進程使用,這樣一來我們之前的時間數據所佔內存就會缺失。 由於內存如同一個棧,佔用內存後這部分會向前擠壓, 0 1 編碼會溢出,那麼這個內存所表示的數據很有可能根據符號位的不同而產生一個負數(二進制符號位 0 代表正數,1 代表負數),而上傳到服務器端負數的毫秒數會解析成一個 1969 年的錯誤日期,這樣一來就拒絕了我們上傳的數據包。


經大量數據的分析統計,出現情況的手機大都內存剩餘量不足,而一些內存剩餘量比較充足的手機使用軟件就不會出現這個問題。


所以說,在使用數據類型的時候一定要門當戶對,而內存的把控也要做到心裏有數才行。



發佈了262 篇原創文章 · 獲贊 817 · 訪問量 61萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章