虛擬內存。這項技術本質上就是對內存地址進行映射,使得進程認為自己擁有連續的,大量的內存,提高內存利用率,降低程序編寫難度。因此,虛擬內存范疇可以劃分為兩類:第一類:將進程占用的內存地址映射到RAM內其他位置,第二類:將進程占用的內存地址映射到磁盤上面。iOS5必定是有第一類虛擬內存的,但沒有第二類。 首先介紹一下虛擬內存。這項技術本質上就是對內存地址進行映射,使得進程認為自己擁有連續的,大量的內存,提高內存利用率,降低程序編寫難度。比如一個程序被系統告知其可用的內存片段是0到100頁。而實際上其占用的內存片段可能是分散的,有可能其占用的真正物理范圍是70-120頁,201頁到240頁,還有10頁在磁盤上面。 因此,虛擬內存范疇可以劃分為兩類: 第一類:將進程占用的內存地址映射到RAM內其他位置。 第二類:將進程占用的內存地址映射到磁盤上面。 而我們通俗講的虛擬內存就是第二類。 第一類由于都是在RAM內進行的,速度很快,并且有專門硬件負責轉換,因而就像是把賓館房間的門牌號換一下而已,對程序的執行沒有任何影響。 第二類由于磁盤的速度讀寫速度太慢,且很多都會有一定讀寫次數的限制,因此,當在磁盤上的頁面要被使用時候,并非直接在磁盤上修改,而是重新搬運回RAM并暫時凍結進程,搬運完成后在RAM內被修改。而RAM內不活動的頁面也會在內存不足時候搬運到磁盤上,為活動的進程提供可用的物理內存。也就是說,磁盤相當于一個倉庫而已,真正干活的地方還是在RAM里面。 這種方式使得在一些小內存的機器上也可以運行一些占用內存大程序,但是不足之處就是慢,卡。 iOS5必定是有第一類虛擬內存的,但是沒有第二類。 首先,如果使用虛擬內存,必定會造成一定的慢,卡,大家在PC上內存滿時候應該體會過。而這一點正是蘋果所不愿意的。蘋果一定要讓一項技術可以流暢的在設備上運行時候才讓它出現。這個很好理解,多任務就是這樣的。 其次,設備會在內存不足時候自動關掉一些后臺程序,如果使用了這項技術,就不會出現內存不足的情況,一旦內存不足,系統會自動將一些不活動進程在內存里數據搬到磁盤里,為活動的程序提供空間,因而也就是說所有的程序都會在后臺保留,最終虛擬內存占用的磁盤空間也會越來越大。而事實上并沒有這種情況。而蘋果本身的設計也就是允許用戶不去關閉這些后臺程序。 當然,你也可以認為iOS的虛擬內存不會提供給應用程序使用。但是如果真的這樣,這虛擬內存又有什么用呢? 除此之外,蘋果也在發布會后的一次WWDC大會上說了:limited memory/virtual memory/no swapfile。也就是說并沒有通俗意義上的虛擬內存。 至于一些開發者發現在terminal里面輸入top時候有一個VM的數值,并懷疑它是虛擬內存大小。那個具體是什么我也不知道,但是我認為并不是的。那個數值確實會隨著程序開的越多而越大,甚至可以到達4G。 下面是我分析的辦法。我將用戶盤和系統盤全部塞滿,發現系統仍然可以正常運行。當我打開那些程序的時候,VM的數值同樣增大,最終同樣可以到4G以上。那這部分空間是在什么地方呢?假如你說是在除系統盤和用戶盤以外的地方,好的,這不是不可能,但我們可以算一下。我是32G的,用戶盤大小29754M,系統盤大小1024M,加起來30778M也就是30G,那剩下的4G往什么地方塞?況且一般來講由于換算原因和其它因素實際可用空間都會小于稱標空間的。 至于iOS系統的內存管理究竟是怎么樣的呢?據我推測是這樣的。 ①當內存不足時候,首先會先叫后臺程序或者系統進程釋放。此時后臺程序會主動釋放一些不太重要的數據資料,比如說圖片信息之類的,保留最重要的狀態信息,與此同時也可能對內存數據進行壓縮。此時,由于占用處理器資源,可能會出現卡頓。 ②當內存依然不足時,系統便開始考慮關閉一些后臺程序了。此時,后臺程序會得到信號,然后開始運行,進行數據的保存,完成后退出,釋放內存。此時,由于會占用處理器以及儲存器,可能會再次導致卡頓。 ③如果問題還不能得到解決,系統就會強制結束前臺程序,同時在/var/logs/AppleSupport/下面留下一堆lowmemory的錯誤報告。這就是常說的閃退的一種原因。 由此也可以說明,iOS系統的內存管理確實很先進,確實是沒有必要去關閉后臺程序。當然,如果你認為①②步驟導致的小卡讓你很不爽,那你還是主動去關吧。 說完了iOS系統的內存管理,下面來說一下用deb安裝的虛擬內存,也就是真正意義上的虛擬內存。 有人說開啟這種虛擬內存完全沒有用,只能是使得內存看上去增大了很多而實際上沒有任何用,還會導致系統不穩。 而我想在此澄清的是: ①虛擬內存并不能增大你設備的內存,只是為正在運行的程序騰出空間。 打個比方,就是虛擬內存并不能增大你工作間的面積,但是它給你提供了一個倉庫,可以將一些當前沒有用的東西搬進去放著,這樣你就可以擁有更多空間干你正在干的事,而倉庫到底不是工作的地方。 ②虛擬內存原本是不會導致設備系統不穩定的,在iOS3時代用過的人都應該知道,這個只是在iOS4時代之后才出現的問題。 ③至于虛擬內存是否會影響設備的壽命,這個我想應該是可以忽略的。我通過查看一天的內存頁面輸出量,也就相當于寫入閃存的數據量。如果不開虛擬內存大概是幾MB,如果開啟大概是200MB左右。如果你開啟的大概是256MB,也就是平均這個區域一天才能全部寫滿一次。 當然也有的鋒友擔心的是對同一個區塊反復擦寫。其實這個是不必擔心的,因為閃存有損耗平衡,它會盡量少寫入擦寫次數多的地方,并且每次重啟虛擬內存文件都是重新創建的。除此以外只有在內存不足的時候才會寫入閃存,而最主要的讀取是不會影響壽命的。而nand閃存寫入次數大概是10萬次,結合總容量,看看有多大影響? 我們使用虛擬內存的主要目的是給當前運行的程序提供更多的物理內存,防止出現系統由于內存不足采取的措施導致的卡頓和閃退,當然也可以在后臺運行更多的程序。 使用虛擬內存一定程度上可能會導致切換程序的卡頓。此時系統正在將磁盤內的數據轉移到內存。 UNIX的虛擬內存是這樣的,在內存并沒有短缺的時候,就開始將內存內一些不活動的頁面寫入磁盤,這樣當進程需要內存時候,可以直接將這部分分配給進程,如果這些不活動頁面沒有被分配,而占用他們的進程又需要修改儲存在其中的數據,則也可以直接修改,因此唯一可能造成卡頓的操作就是激活有頁面被交換到磁盤上去的進程,而即便這樣,也只需要將磁盤上一部分數據讀取到內存就可以。經過測試,touch4閃存讀取速度是接近40MB/s,也就是說,假設一個進程占用了40M內存并被全部交換到閃存里,最多這個進程也就被暫停1s。而事實上,很少有程序會占用到40M內存,基本上就是游戲,并且一般很少會全部交換到閃存,就算這樣,激活這個進程也沒必要把全部頁面都交換到內存里,除此以外,還記得切換程序的過渡動畫嗎,貌似也有1s吧。因此,幾乎感覺不到卡頓的,就算有一點,也沒關系啊,總比后臺被關掉和前臺閃退好吧。 因此,虛擬內存還是有很大好處的,并不是只是讓內存看上去大一點的東西。 下面,我就來為大家剖析一下deb虛擬內存原理是什么。 其實所有的虛擬內存的deb的原理完全一樣,因此橫向比較其穩定性沒有任何意義。簡而言之,其功能只是開啟了系統原生就有的功能而已。 所有的虛擬內存deb解包后都有一個放在/system/library/launchdeamons/里面的一個plist文件。這個路徑存放的是所有開機啟動的進程配置文件。一般這個plist指向啟動的程序就是在/sbin/里面的dynamic_pager。也有的是指向vm,而這個vm就是deb安裝后放在sbin里面的一個程序,本質上和dynamic_pager是一樣的。而其他文件不過就是一些輔助用途,比如fm用來釋放內存,還有一個關閉虛擬內存加密用的。 下面我們來講一講這個dynamic_pager到底是個什么東西。 其實它并不是虛擬內存的進程,虛擬內存不需要進程,是操作系統的功能。這個進程的功能是和系統通信,負責創建,刪除虛擬內存文件。如果你強行干掉這個進程,虛擬內存仍然可用,但不能增加減少交換文件數量。一旦交換文件寫滿,當前的程序會卡死。 在terminal里面登陸root后直接輸入dynamic_pager回車就可以開啟虛擬內存。這個進程有這么幾個選項: -F 單個虛擬內存交換文件大小,默認為64m,使用時候在后面輸入文件字節數。 -S 虛擬內存交換文件路徑和名稱,默認在/var/vm,默認文件名swapfile編號。 -H 設置當swapfile的總剩余空間低于多少字節時候創建新的交換文件。 -L 設置swapfile總剩余空間多于多少字節時刪除空閑的交換文件 -P 優先級,不過貌似沒什么用。 講清楚了這個程序的作用,下面說說它的來歷。 很多人以為這個是系統自帶的,其實不是的。這是越獄后cydia自動安裝上去的。大家打開cydia,在剛越獄完后就安裝的軟件包里面可以找到,有一個點開后在文件系統一項可一看到這個程序。 總之,這個dynamic_pager是十分重要的,盡管不是原生的,但是由其作用是開啟系統的虛擬內存,我們可以知道,iOS原生就支持虛擬內存,只不過是被蘋果拿掉了而已。 說完了這個,我再給大家講一下虛擬內存交換文件的管理方法。 經過我的實驗和查詢一些資料,我總結出來了其管理的特點。 其映射方式很有可能直接由內存地址映射到閃存的物理地址,也就是說其讀寫不用經過文件管理系統,直接按照閃存的物理地址寫入。因此你將虛擬內存文件刪除不會影響虛擬內存的工作。而其生成這個文件的唯一目的是占個位置,讓操作系統和別的程序知道這個區域是有用途的,防止其他程序在這塊地址創建文件導致內存數據被篡改。 除此以外,無論你怎么設權限,就算全部權限取消,就是每個用戶組讀取,寫入,執行都取消,也不影響虛擬內存,交換文件一樣被修改。很有可能其完全不受文件管理系統控制,完全獨立開來。因此修改其權限沒有什么意義。很多人說修改為777,事實上000還更穩定。 最后,也就是大家最關心的,為什么虛擬內存不穩定,原理見下。 虛擬內存造成系統不穩定的直接原因就是重要進程崩潰和出錯。 崩潰還算一種比較好的結果。 如果是普通程序,就是閃退,safari最典型。 如果是springboard,就是安全模式。 如果是launch,就是重啟。 進程出錯可能會導致當機,而最為嚴重的是對某些文件的錯誤修改,也就是虛擬內存導致白蘋果的重要原因,當然我還遇到過所有程序消失之類的現象。 因為每次進程崩潰都會在/var/logs/AppleSupport下面留下錯誤報告。經過長時間的搜集和整理,發現其主要都是一類錯誤,就是SIGABRT或者SIGBUS。這都是常見的內存錯誤,一般都是由于進程請求了一個錯誤的內存地址導致的,錯誤報告附帶了這個地址。我還發現,其請求的地址都是超出了RAM范圍的。也就是說其請求的是被交換到閃存上的部分。 一個開啟了虛擬內存的機器,當出現這種情況時,系統會檢測出進程請求的地址溢出,此時會出現中斷,也就是處理器停止處理當前正在處理的任務,轉而處理一個臨時新增的任務,也就是將這個地址映射到的磁盤區域的數據轉移到內存里面,然后再恢復之前的任務。也就是說,出現這種情況時候很可能此時系統并沒有中斷,當前正在執行的任務沒有停止,沒有進行數據的轉移,最終導致內存地址出錯。這個同樣可以解釋進程出錯,可能數據轉移還沒有完成,原先的任務卻開始運行,此時溢出的內存地址已經映射到內存區,不會出現內存錯誤,但是數據轉移沒有完成,也就是說這塊區域的數據并不是全是閃存里的數據,結果就是進程出錯。 造成這個的因素是這樣的。 蘋果為了流暢,反應靈敏可謂無所不用極其。大家也知道ios的用戶界面渲染優先級非常高,完全有可能蘋果直接把用戶界面渲染也作為了一個中斷。中斷也是有優先級的。如果這個中斷優先級高于虛擬內存的,就可能出現上面講的情況,數據還沒有轉移完,虛擬內存的任務卻被停止了,而處理器開始處理用戶界面渲染的任務。如果剛好用戶界面渲染的數據被交換到了閃存上,而沒來得及轉移到RAM內,就會出現內存地址溢出或者進程出錯,最典型就是安全模式和花屏。而Springboard和用戶界面渲染關系最為密切,這樣也可以解釋為什么這個進程崩潰的次數最多。 要想解決這個問題,就要降低用戶界面渲染優先級或者取消其中斷的權利,當然也可以提高虛擬內存中斷的優先級。這一步仍然有待研究來實現。 |