iOS開發筆記— 資料庫、Crash、記憶體問題分析
前言
分享iOS開發中遇到的問題,和相關的一些思考,本次內容包括:UIKit的iOS11問題、資料庫問題定位、線上Crash處理、記憶體問題分析。
正文
1、iOS 11的UITabbar的高度異常
問題描述:iOS 11+iPhone,在橫豎屏切換的場景下,UITabbarViewController的底部欄UITabbar會出現高度異常。
問題定位:經過除錯發現,從豎屏到橫屏的時候,系統會改變UITabbar的高度;而我們的底部欄高度是自定義的值,故而會導致系統修改後的高度與自定義值不相同的情況。
解決方案,KVO:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if (self.tabBar.height != KSTabBarHeight) { self.tabBar.height = KSTabBarHeight; self.tabBar.bottom = SCREEN_HEIGHT; }
Stackoverflow的類似情況
2、CoreData資料庫升級時間長
問題描述:App在升級的時候會對CoreData資料庫進行一次遷移,而某些使用者反饋升級時間長達數分鐘。
問題定位:CoreData資料庫遷移使用的是系統提供的自動遷移,經過本地測試,確實存在資料庫較大的情況下,升級時間較長的問題。
那麼如何確定資料庫是哪些表是瓶頸?
使用者的資料庫比較大,不可能進行整個資料庫上傳操作;而CoreData並不支援獲取某個表的大小。
可以採取一種方案:使用者上報資料庫每張表的行數,本地通過工具求出每張表的平均值,用以估算每張表的大小。
找到可以匯出沙盒本地沙盒的App活躍使用者(比如說運營、產品),用sqlite3_analyzer對資料庫進行分析,得到每張表大小,再除以行數,得到每張表每行的平均值。
(不能通過行數直接判斷資料庫大小,因為表的列數不確定;也不能通過列大小*行數得到表體積,因為某些欄位為空)
修復方案:
-
對瓶頸的表進行行數和體積雙重控制;
-
對某些行數較多但表體積小的表建索引;
引用:
sqlite資料庫分析
sqlite3_analyzer安裝
Appropriate Uses For SQLite
sqlite索引
Customizing the Migration Process
3、objc_msgSend的Crash分析
問題描述:objc_msgSend是常見的一種Crash,這次的堆疊如下
這類由UIKit引起的Crash通常是在回撥業務層時,對應的target已經被釋放,於是在objc_msgSend的時候就會發生Crash。
暫存器和模組載入地址
問題定位:在本例中,檢視上圖知道,lr暫存器的地址是在第一個模組的載入區間內,以此作為線索。
用以下指定,進行手工符號化:
atos -o XXX arm64 0x000000010134d36c -l 0x1000fc000(XXX是二進位制名字)
最終定位到問題,具體的程式碼類似:
[self.delegete remove];self.data = ...
在這種情況下,self.delegate在remove掉之後self之後,self已經被釋放,下面的self.data再進行賦值操作,就會出現異常情況。
解決方案:把 [self.delegete remove]; 放到最後一行。
後記:ios-Swift/Object C開發 稽核上架交流群 869685378 歡迎各位大牛來分享交流 IOS,馬甲包,低要求,內容開發沒有限制,報酬豐厚,實力誠信 Q:782675105
該問題只出現在iOS 8。在iOS 11的機型上,通過除錯我們可以獲取到self.data=…這一行在執行時,關於self的記憶體引用情況:
autoreleasepool和thread都會持有self,保證self在本次執行過程中不釋放。故此猜測該問題蘋果已經發現,並且在iOS 8後續的版本已經修復。
4、記憶體相關問題
實際場景涉及到業務,所以抽象成程式碼來進行分析。
場景1
下面這段程式碼是否能夠正常執行?
如果可以,結果是什麼?
如果不可以,是為什麼?
- (void)viewDidLoad { [super viewDidLoad]; SInt16* buffer = NULL; SInt16* p = &buffer[15]; NSLog(@"tmp %d", p);}
場景2
下面這段程式碼是否能夠正常執行?
如果可以,結果是什麼?
如果不可以,是為什麼?
- (void)viewDidLoad { [super viewDidLoad]; char *pBuf = malloc(5); memcpy(pBuf, "aaabbbcccddddeeefff", 10); puts(pBuf);}
分析:
場景1:
此處有兩個trick:
1、p是否能夠正常賦值,以及賦何值;
2、指標型別是SInt16*, 計算地址要注意;
[] 是下標運算子,根據運算元和偏移量,獲取指定地址的值;
在此題之中,buffer[15]等於*(buffer + 15);
&buffer[15] 等於&(*(buffer + 15));
& 是取址運算子,返回運算元的記憶體地址;
&buffer[15] = &(*(buffer + 15)) = buffer + 15
所以p = &buffer[15] = buffer+15 = 0+15*sizeof(SInt16) = 30
故而答案是能正常執行,結果是”tmp 30″。
場景2:
申請了一塊較大的記憶體,在memcpy的時候,偶然情況下會出現越界的情況。但是因為堆記憶體空間到棧記憶體空間的距離不固定,不一定會出現crash的情況。
上面的題目本質是堆記憶體訪問越界。
故而上述程式碼大多數情況下輸出aaabbbcccd,少數情況下不可預知。
總結
2018年的忙碌情況超過我想象,長時間不更新iOS開發筆記讓我都忘了還有這個專題所在。
我有個習慣,開發中遇到問題,超過十分鐘還沒解決的時候,就會記錄下來,這樣是開發筆記專題的雛形。
而在加入新公司的第二個年頭,我慢慢已經在iOS上的收穫越來越少。
從筆記的新增情況來看,就可以發現:每天大多數是重複性勞動!
嘗試看過一些iOS相關的書籍,但總感覺收穫不大。
今年我選擇把更多的業餘學習時間分配給Metal,詳見Metal入門教程總結。
落影loyinglin
相關文章
- 探究 iOS 記憶體問題iOS記憶體
- 使用 Chrome 開發者工具分析記憶體問題Chrome記憶體
- SQLServer記憶體問題分析SQLServer記憶體
- 記憶體資料庫如何發揮記憶體優勢?記憶體資料庫
- 記憶體洩漏引起的 資料庫效能問題記憶體資料庫
- iOS 問題整理07----記憶體管理iOS記憶體
- 分析師解讀記憶體資料庫MemSQLSP記憶體資料庫SQL
- 【記憶體資料庫】TimesTen記憶體資料庫
- 資料庫新兵:分散式實時分析記憶體資料庫eSight資料庫分散式記憶體
- PG資料庫記憶體告警了怎麼分析資料庫記憶體
- pprof 分析mysqld 記憶體呼叫(筆記)MySql記憶體筆記
- Windbg分析高記憶體佔用問題記憶體
- Java記憶體問題 及 LeakCanary 原理分析Java記憶體
- 【大頁記憶體】Oracle資料庫配置大頁記憶體記憶體Oracle資料庫
- iOS開發-屬性的記憶體管理iOS記憶體
- iOS開發之記憶體與快取iOS記憶體快取
- 【虹科乾貨】使用記憶體資料庫解決三個資料庫效能問題記憶體資料庫
- X86環境大記憶體下資料庫啟動問題分析與處理記憶體資料庫
- 利用Windbg分析高記憶體佔用問題記憶體
- iOS 記憶體管理iOS記憶體
- 筆記-更深層次的瞭解iOS記憶體管理筆記iOS記憶體
- C結構體中資料的記憶體對齊問題結構體記憶體
- 故障分析 | 租戶 memstore 記憶體滿問題排查記憶體
- Oracle - 資料庫的記憶體結構Oracle資料庫記憶體
- Oracle - 資料庫的記憶體調整Oracle資料庫記憶體
- 瀚高資料庫記憶體結構資料庫記憶體
- 使用 Chrome 開發者工具的 Memory 標籤頁分析記憶體洩漏問題Chrome記憶體
- JavaScript變數,資料和記憶體的相關問題JavaScript變數記憶體
- iOS 解決設定rootViewController 記憶體不釋放問題iOSViewController記憶體
- 2020.10.8 效能課堂筆記-記憶體瓶頸分析筆記記憶體
- 大資料開發筆記大資料筆記
- ThreadLocal記憶體洩漏問題thread記憶體
- 排查Java的記憶體問題Java記憶體
- 記憶體分配問題處理記憶體
- 記憶體洩漏問題分析之非託管資源洩漏記憶體
- 分析ThreadLocal的弱引用與記憶體洩漏問題thread記憶體
- 【C】 42_記憶體操作經典問題分析 二記憶體
- 【C】 41_記憶體操作經典問題分析 一記憶體