Post

Deep Memory of iOS

Memory Footprint

graph TD
  subgraph Typical_app_memory_profile
    Dirty_memory
    Clean_memory
    Compressed
  end

graph LR

  subgraph Memory_warnings
    App_is_not_always_the_cause
    Compressor_complicates_freeing_memory
    Prefer_policy_changes_over_cache_purging
  end

  Memory_warnings -.-> Pages

  subgraph Pages
    Page_types --> Dirty_memory
    Page_types --> Clean_memory
    Typically_16KB
  end
  
  subgraph Memory_mapped_files
    File-backed_memory
    Read-only_files_are_clean
    Kernel_manages_when_file_is_in_RAM
  end

  Memory_mapped_files --> files

  subgraph files
    image.jpeg
    Blob.data
    Training.model
  end
  

  Clean_memory --> Data_that_can_be_paged_out_of_memory
  Data_that_can_be_paged_out_of_memory --> Memory_mapped_files
  Data_that_can_be_paged_out_of_memory --> __DATA_CONST

  subgraph Frameworks
  __DATA_CONST
  __DATA
  __DATA_DIRTY
  end

  Dirty_memory --> Memory_written_by_an_app
  Memory_written_by_an_app --> All_heap_allocations
  Memory_written_by_an_app --> Decoded_image_buffers
  Memory_written_by_an_app --> __DATA
  Memory_written_by_an_app --> __DATA_DIRTY

  All_heap_allocations --> malloc
  All_heap_allocations --> Allay
  All_heap_allocations --> NSCache
  All_heap_allocations --> UIViews
  All_heap_allocations --> String

  Decoded_image_buffers --> CGRasterData
  Decoded_image_buffers --> ImageIO
  

  subgraph Memory_compressor
    No_traditional_disk_swap
    Compresses_unaccessed_pages
    Decompresses_pages_upon_access
  end

  Memory_compressor --> Pages

Pages

是有多个Page组成, 每个Page占16KB, 如果不够就会申请更多.

Memory is use = Number of Pages X Page size

Clean & dirty pages

Clean Memory
内存映射文件(Memory-mapped files):指那些从磁盘加载到内存中但没有被应用程序写入或修改的文件,如图片、数据块、训练模型等。 只读数据:包括应用程序中的常量数据或只读的全局变量,如字符串、常量数组等。

一句话, Data that can be paged out of memory 可以被操作系统从内存中分页出去,以便回收内存空间。被分页出去的数据通常被存储在磁盘的其他区域,如分页文件(page file)或交换分区(swap partition 在iOS 中不存在)中,以便在需要时重新加载到内存中.

Dirty Memory
动态分配的对象:通过malloc、calloc等方法动态创建的对象,如动态分配的字符串、数组等。 对象属性的修改:对已经创建的对象进行修改或更新操作,包括属性的赋值、数组元素的修改等。 图像缓冲区的解码:对图像进行解码操作,将压缩格式转换为内存中的原始像素数据。 缓存数据:由应用程序自己实现的缓存机制,用于存储经常访问的数据,如网络请求的结果、计算结果等。

一句话, Memory written by an app 主要来自app创建的数据.

Frameworks

A good practice is to use the singletons and the global initializers of the frameworks to alleviate the amount of dirty memory generated by their usage.

使用框架的单例模式和全局初始化器是一个不错的实践,可以减少它们使用过程中产生的脏内存量。 单例模式是一种设计模式,它确保一个类只有一个实例,并提供一个全局访问点。当框架中的对象以单例模式创建时,它们会在内存中一直存在,减少了频繁的内存分配和释放操作,从而减少了脏内存的生成。 全局初始化器是指在框架被链接或类被加载时运行的初始化器。通过在全局初始化器中执行一些必要的操作和初始化步骤,可以减少框架使用过程中产生的脏内存。

一句话, 要达到这个效果, 就类似静态变量被定义为const (const 编译时被确定)不可修改的设计范式.

如果只是设计了单例, 而里面的属性方法都是动态创建和修改, 最终也是落在dirty memory中了.

Compressed

iOS 7 开始提供这个能力

在操作系统中,内存是有限的资源。为了最大限度地利用可用内存空间,内存压缩技术被引入。内存压缩器会监视系统的内存使用情况,并根据需要对内存中的页面进行压缩。未使用的页面通常会占用较多的内存空间,通过将这些未使用的页面进行压缩,可以减少内存的占用。

当应用程序需要访问被压缩的页面时,内存压缩器会在访问前对页面进行解压缩。这个过程是透明的,应用程序无需感知页面是否被压缩。通过在访问时进行解压缩,内存压缩器确保应用程序能够正常地访问所需的数据。

内存压缩技术对于具有大量未使用页面的系统或应用程序特别有效。它可以减少内存占用,延长可用内存空间的寿命,并提高系统的整体性能。然而,需要注意的是,内存压缩和解压缩过程会增加CPU的负担,并可能导致轻微的访问延迟。

一句话,被压缩的内存可能在使用的时候突然暴增, CPU暴涨都可能会发生.

Memory warnings

当app的内存紧张的时候, 应该如何处理? 那为什么会出现内存紧张的情况呢?

graph TD
  subgraph Typical_app_memory_profile
    Dirty_memory
    Clean_memory
    Compressed

    subgraph id[Memory_warnings]
      App_is_not_always_the_cause
      Compressor_complicates_freeing_memory
      Prefer_policy_changes_over_cache_purging
    end
    style id fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5


  end
This post is licensed under CC BY 4.0 by the author.