iOS內存深刻探索之VM Tracker

什麼是VM Tracker

VM Tracker是Xcode Instruments自帶的一個內存分析工具,能夠幫助你快速查看虛擬內存塊的用量狀態以及根據虛擬內存塊的tag進行分類。若是你想知道關於虛擬內存的相關知識,能夠先閱讀探索iOS內存分配這篇文章,若是你對虛擬內存以及VM Region不太瞭解的話,閱讀下面的內容可能會有些障礙。想要使用VM Tracker,使用Instruments的Allocations模版便可。若是模版自帶的VM Tracker不顯示信息,能夠用右邊的加號再添加一個VM Tracker。html

VM Tracker列屬性解析

上面是一個空的iOS App的VM Tracker示意圖。一共有9列,下面我來一一解釋它們的含義。

  • % of Res, 當前Type的VM Regions總Resident Size佔比。
  • Type,VM Regions的Type,AllDirty算是統計性質的Type,__TEXT表示代碼段的內存映射,__DATA表示數據段的內存映射。MALLOC_TINY,MALLOC_LARGE,CG Image等Type能夠從VM Region的Extend Info中讀取出來,後面會着重介紹。
  • # Regs,當前Type的VM Region總數。
  • Path,VM Region是從哪一個文件映射過來,由於有些相似於__DATA和mapped file的內存塊是從文件直接映射過來的。
  • Resident Size,使用的物理內存量。
  • Dirty Size,使用中的物理內存塊若是不交換到硬盤保存狀態就不能複用,那麼就是Dirty的內存塊,好比你主動malloc出來的內存塊,若是不保留其中的狀態就把它給別人用,那你確定就沒法恢復這個內存塊的信息,因此它是Dirty的。若是是一個映射到內存的文件,就算使用它的內存塊,仍是能夠從新從磁盤載入文件到內存的,因此是非Dirty的,好比最上面圖中的mapped file那一行,你能夠看到Dirty Size是0。
  • Swapped Size, 在OSX中,不活躍的內存頁能夠被交換到硬盤,這是被交換的大小。在iOS中,只有非Dirty的內存頁能夠被交換,或者說是被卸載。
  • Virtual Size,VM Regions所佔虛擬內存的大小
  • Res. %,Resident Size在Virtual Size中的佔比

使用vm_allocate自定義VM Region

咱們可使用vm_allocate方法申請一塊虛擬內存。下面是具體代碼。ios

vm_address_t address;
vm_size_t size = 1024 * 1024 * 100;
vm_allocate((vm_map_t)mach_task_self(), &address, size, VM_MAKE_TAG(200) | VM_FLAGS_ANYWHERE);
複製代碼

上面的代碼申請了一塊100M的虛擬內存,(vm_map_t)mach_task_self()表示在本身的進程空間內申請。size的單位是byte。 VM_MAKE_TAG(200)是給你申請的內存塊提供一個Tag標記。我這裏提供了一個200數值做爲標記,後面我會具體介紹這個數值在VM Tracker中的做用。最後咱們用VM Tracker看一下咱們本身分配的虛擬內存塊。 app

你可能會注意到這塊內存塊的Resident Size和Dirty Size都是0KB,由於咱們並無使用這塊內存,因此並無虛擬內存被關聯到物理內存上去。你能夠嘗試使用這塊內存,而後去VM Tracker觀察變化。好比使用下面的方式填充內存塊。ide

for (int i = 0; i < 1024 * 1024 * 100; ++i) {
  *((char *)address + i) = 0xab;
}
複製代碼

VM Region的Type

接下來咱們來介紹內存塊的Type,我曾經思考好久VM Tracker是如何識別出每一個內存塊的Type的。好比MALLOC_TINY,MALLOC_SMALL,ImageIO等等。答案就在vm_allocate方法的最後一個參數flags。flags能夠分紅2個部分。VM_FLAGS_ANYWHERE屬於flags裏控制內存分配方式的flag,它表示能夠接受任意位置的內存分配。它的宏定義以下。工具

#define VM_FLAGS_ANYWHERE 0x0001
複製代碼

從定義能夠看出,2個字節就能夠存儲它,int有4個字節,還剩下2個就能夠用來存儲標記內存類型的Type了。蘋果提供了VM_MAKE_TAG宏幫助咱們快速設置Type。VM_MAKE_TAG實際上作了一件很簡單的事情,把值左移24個bit,也就是3個字節,因此係統留給了咱們1個字節來表示內存的類型。下面是VM_MAKE_TAG的宏定義。spa

#define VM_MAKE_TAG(tag) ((tag) << 24)
複製代碼

實際上蘋果已經內置了不少默認的Type,下面列出一部分。rest

#define VM_MEMORY_MALLOC 1
#define VM_MEMORY_MALLOC_SMALL 2
#define VM_MEMORY_MALLOC_LARGE 3
#define VM_MEMORY_MALLOC_HUGE 4
#define VM_MEMORY_SBRK 5// uninteresting -- no one should call
#define VM_MEMORY_REALLOC 6
#define VM_MEMORY_MALLOC_TINY 7
#define VM_MEMORY_MALLOC_LARGE_REUSABLE 8
#define VM_MEMORY_MALLOC_LARGE_REUSED 9
複製代碼

若是咱們使用VM_MEMORY_MALLOC_HUGE來做爲Type,再用VM Tracker觀察會怎麼樣呢?下面是內存分配的代碼。code

vm_address_t address;
vm_size_t size = 1024 * 1024 * 100;
vm_allocate((vm_map_t)mach_task_self(), &address, size, VM_MAKE_TAG(VM_MEMORY_MALLOC_HUGE) | VM_FLAGS_ANYWHERE);
複製代碼

下面是VM Tracker的截圖。 cdn

很明顯VM Tracker認出了這塊內存,而且將它的Type設定爲MALLOC_HUGE。若是你想使用vm_allocate來分配和管理大內存,也能夠設置一個Type,方便快速定位到本身的虛擬內存塊。htm

總結

本文主要介紹了VM Tracker中關於虛擬內存的一些概念,以及如何自行分配虛擬內存。瞭解了這些以後,在分析內存暴漲或者泄漏時就有了新的思路,而不單單是侷限於基於malloc內存塊的內存分析了。

相關文章
相關標籤/搜索