A quick summary of iOS memory

1. Basic concepts of memory

Physical memory vs. virtual memory

  • Physical Memory: Refers to the Memory space obtained from Physical Memory modules, corresponding to virtual Memory. The main functions are: provide temporary storage space for the operating system and various programs when the device is running; The iPhone 6 and 6 Plus and their predecessors had 1 gigabyte of ram, while the newer iPhone XS and XS Max had 4 GIGABytes of ram.
  • Virtual Memory: A technique for Memory management in computer systems. It provides a consistent, private address space for each process. It protects the address space of each process from being destroyed by other processes and reduces the complexity of memory management. The virtual memory size is 4GB for 32-bit devices and 4GB x 4GB for 64-bit devices (5s or later).
  • Virtual memory is the sum of all the memory space in which a process is running, and some of it may not be in physical memory;

2. Segment-page storage

  • At present, most common computer memory management uses segment-page storage structure; The user program is segmented first, and then paging within each segment; The page is the most basic unit of storage. With the arm64 architecture on iOS devices, the page size is 16KB.
  • The physical address is obtained by changing the logical address (segment number + page number + page address). Thus, in a segmented page structure, memory must be accessed three times to get data or instructions;
  • When a process accesses a virtual memory Page, but the corresponding physical memory does not exist, it will trigger a Page Fault, load the required data or instructions from disk to the physical memory Page, establish the mapping relationship, and then restore the site, the program itself is not aware of;

3, Swap In/Out & Page In/Out

  • There is an area inside the disk called Swap Space. The MMU writes the contents of unused memory blocks to the interactive Space (disk). This is called Swap Out. And when you need to read from Swap Space into memory, that’s Swap In; Both Swap in and Swap out operations are time-consuming. Frequent Swap in and Swap out operations greatly affect system performance.

  • Page In/Out is a similar concept to Swap In/Out, except that Page In/Out writes some Page data to/from memory back to disk interaction. Swap In/Out writes the entire address space to/from memory back to the disk interaction area. They’re all interactive mechanisms.

  • MacOS supports this type of switching, but iOS does not; There are two main considerations:

    • Flash read and write times of mobile devices are limited, and frequent write will reduce the lifetime.
    • Compared to PCS, mobile devices have limited flash memory space (15 years 6s minimum storage 16GB, maximum 128GB; 19 Year XS Max minimum 64GB, maximum 521GB)

4, To be continued

  • General-purpose computer (Mainframes and dedicated computers are excluded) storage is typically set up in multiple tiers, from the Cache closest to the CPU all the way to disk, which are becoming slower and cheaper.
  • In order to make full use of hardware resources, Cache and Swap mechanism came into being. Cache mechanism is a mechanism that trades space for time. The Swap mechanism uses time for space;
  • However, iOS system replaces swap mechanism with Compressed memory mechanism.

Basic concepts of iOS memory management

1. IOS memory partition

The ranges from high address to low address are as follows:

  • Stack: automatically allocated by the compiler, storing function parameter values, local variable values, etc., after the scope is executed, it will be recalled by the system; (Stack address assigned from high to low)
  • Heap: usually allocated and released by programmers to hold memory segments that are dynamically allocated during program execution; Objective-c objects in iOS are stored here, managed by ARC; (Heap addresses are assigned from low to high)
  • Global area Static area: allocated by the compiler, mainly storing global variables and static variables, released by the system after the end of the program; It is mainly divided into two areas:
    • BSS zone: uninitialized global and static variables;
    • Data area: initialized global and static variables;
  • Constant area: store constant, such as constant string, after the program is released by the system;
  • Code area: store the binary code of the function body, which will be released by the system after the program is finished;

2. Memory page types: Clean and Dirty

  • Memory pages are classified as Clean and Dirty according to their allocation and usage status. Clean pages can be recycled, while Dirty pages cannot.

    int *array = malloc(20000 * sizeof(int)); // Array [0] = 32 array[19999] = 64 // Step 3Copy the code
  • The first step, apply for a length of 80000 bytes of memory space, according to a page of 16KB, you need 6 pages of memory to store. When these pages are opened up, they are Clean;

  • Second, when data is written to the memory on page 1, the memory on page 1 becomes Dirty.

  • Third, when data is written to memory on the last page, the page also becomes Dirty.

3, VM Region

  • All memory in an iOS process is made up of many VM regions;

  • A VM Region is a contiguous memory page (in the virtual address space). The structure of a VM Region is as follows

    struct vm_region_submap_info_64 { vm_prot_t protection; /* present access protection */ vm_prot_t max_protection; /* max avail through vm_prot */ vm_inherit_t inheritance; /* behavior of map/obj on fork */ memory_object_offset_t offset; /* offset into object/map */ unsigned int user_tag; /* user tag on map entry */ unsigned int pages_resident; /* only valid for objects */ unsigned int pages_shared_now_private; /* only for objects */ unsigned int pages_swapped_out; /* only for objects */ unsigned int pages_dirtied; /* only for objects */ unsigned int ref_count; /* obj/map mappers, etc */ unsigned short shadow_depth; /* only for obj */ unsigned char external_pager; /* only for obj */ unsigned char share_mode; /* see enumeration */ boolean_t is_submap; /* submap vs obj */ vm_behavior_t behavior; /* access behavior hint */ vm_offset_t object_id; /* obj/map name, not a handle */ unsigned short user_wired_count; };Copy the code
  • VM Region contains the following important information:

    • Pages_resident: number of physical memory pages in use
    • Pages_dirtied: number of Dirty memory pages
    • Pages_swapped_out: number of pages in Swapped
  • You can get an idea of the actual physical memory usage of VM Region by looking at PAGes_dirTIED and PAGes_swapped_OUT.

3. IOS memory management mechanism

1. OC memory management

  • Objective-c provides two types of memory management: MRC (manual reference counting) and ARC (automatic reference counting)
  • Basic principles of Objective-C memory management: Who creates, who frees, who references, and who manages;
  • ARC was widely accepted after iOS 5, and it was nice not to have to manage reference counts; With ARC, happy to write OC; However, ARC only manages memory for Objective-C objects, and memory allocation for CoreFoundation objects, CoreGraphics objects, and C/C++ is still up to the developer to manage.

2. System memory classification

Starting from iOS7, the system uses Compressed Memory mechanism to optimize Memory usage, and the Memory types can be divided into three types:

  • 4. Clean Memory that can be freed or rebuilt, including:

    • Code
    • Framework, every framework has it_DATA_CONSTSection, which corresponds to a framework when the App uses it at runtime_DATA_CONSTMemory will change from Clean to Dirty.
    • Memory-mapped files (files that have been loaded into memory)
  • Dirty Memory: Memory that has been written to, including:

    • Objects in all Heap allocations
    • Decoded Image buffers
    • Frameworks (in the framework_DATASegment and_DATA_DIRTYParagraph)
    Dirty Memory is generated during the use of the framework. Using singletons or global initializations reduces Dirty Memory. This is because once created, the singleton is not destroyed, and the global initialization method is executed at class load time.Copy the code
  • Compressed Memory:

    • By Compresses unemail exchange with pages.

    • Decompresses pages upon access when needed

    • Advantages: Reduced inactive memory footprint; Reduce disk I/O loss; Compression/decompression is very fast, can minimize CPU time overhead; Supports multi-core operation.

    • For example, when we use NSDictionary to cache data, assuming that we have used 3 pages of memory, it may be compressed to 1 page when we do not access it, and will be decompressed to 3 pages when we use it again.

  • The Code for Clear Memory and Dirty Memory is as follows:

    Dirty Memory NSString *str1 = [NSString stringWithString:@"Welcome!"] ; Clear Memory NSString *str2 = @"Welcome!" ; Clear Memory char *buf = malloc(100 *1024 *1024); Clear Memory char *buf = malloc(100 *1024 *1024); For (int I = 0; i < 3 * 1024 * 1024; ++ I) {// Dirty Memory buf[I] = rand(); }Copy the code
  • Note: In the case of tight Memory, Clean Memory can be freed, but Dirty Memory cannot be freed. Therefore, the more Dirty Memory, the worse the stability of App.

3,Jetsammechanism

  • Jetsam is a management mechanism adopted by the operating system to control the overuse of memory resources. Jetsam is a standalone process that kills apps that are not high priority or consume too much memory. After the App is killed, some data information is recorded and saved to the log.

  • App priority can be understood as follows: foreground App > background App; Low memory > high memory;

  • The logs generated by Jetsam can be found in the phone Settings -> Privacy -> Analysis. The logs start with JetsamEvent and have fields such as pageSize, CPU Time, and so on.

  • Look at the system logs starting with JetsamEvent in Settings > Privacy > Analysis and pay attention to two important pieces of information.

    "pageSize" : 16384// Memory pages reached the upper limit"rpages" : 948// The number of pages occupied by the App"reason" : "per-process-limit"// The memory occupied by the App exceeds the system memory limit for a single App.Copy the code
    • instructions: This memory “upper limit” calculation: pageSizerpages = 16384948/1024/1014 = 14.8MB, this App should be killed because of its low priority, after all, the maximum memory usage of App cannot be less than 15MB.

4. Memory warning

  • There are three Memory Warning modes:
    • UIApplicationDelegatetheapplicationDidReceiveMemoryWarning:
    • View controllerUIViewControllerthedidReceiveMemoryWarning
    • UIApplicationDidReceiveMemoryWarningNotification notice
  • Memory warning does not necessarily appear before OOM. It is possible that a large amount of Memory was allocated at that time, and the main thread was busy with other things, so the OOM may occur without experiencing the Memory Warning. It is also possible that even after several Memory warnings, the OOM may not appear a few seconds after the last Memory Warning (maybe 1-2 minutes).
  • Not all memory warnings are caused by apps. For example, on devices with low memory, memory warnings can occur when you answer a phone call.

4. Common memory problems

1, FOOM

  • FOOM (Foreground Out Of Memory) refers to the fact that the App is forced to kill because it consumes too much Memory in Foreground. To the user, it behaves like Crash.

  • As early as August 2015, Facebook proposed a FOOM detection method. The general principle is that after excluding various cases, the remaining cases are FOOM. How does Facebook determine if the FOOM method was present during the last startup?

    • 1.App has not been upgraded
    • 2.App does not call exit() or abort() to exit
    • 3.App did not Crash (Crash callback dependent on its own CrashReport component)
    • 4. The user does not forcibly cancel the App
    • 5. The system is not upgraded or restarted
    • 6. The App is not running in the background (depending on ApplicationState and foreground switching notifications)
    • 7.App FOOM appears (depending on ApplicationState and background switch notifications)
  • The possibility of false positives in the screening method, because some cases were forcibly killed by the system, but we could not capture the information, and they may also be classified into OOM; The cases that are forcibly killed by the system are OOM and watchdog(Code 0x8BadF00d).

  • The key to finding the FOOM problem is as follows: Monitor the growth of App memory usage, dump the memory information, obtain the object name, object number, and memory value of each object when receiving the memory warning notification, and report it to the server at an appropriate time. Strengthen the monitoring of large memory allocation.

2. Memory leaks

  • Memory Leak: refers to the Memory space that is applied for and not recycled after it is used. If there are many Memory leaks, the quality of the App will be greatly affected.

  • Currently, the main cause of memory Leaks is circular references (objects in the heap memory reference each other and have no chance to release each other). Currently, Leaks is detected using the Instrument tool during debugging, and MLeaksFinder is reported online.

  • How to avoid memory leaks is explained later

3, WKWebview blank screen

  • The WKWebview white screen problem, strictly speaking, is a memory problem; The previous UIWebview crashed because of memory usage, but WKWebview did not Crash, it will be blank screen;

  • WKWebView is a multi-process component. Network Loading and UI Rendering are performed in other processes. When WKWebView occupies a large memory, the WebContent Process will Crash, resulting in a blank screen.

  • Solutions:

    • KVO listens for the URL, and when the URL is nil, it is reloaded

    • On the aborted process callback, reload

      / / this method apply iOS9.0 above - (void) webViewWebContentProcessDidTerminate: (WKWebView *) webView NS_AVAILABLE (10 _11, 9 _0) {/ / reload}Copy the code

4. Wild pointer problem

  • Wild pointer: pointer to a deleted object or restricted memory area; There are few such problems now, mainly from two aspects

    • From MRC era to ARC era, OC object management is greatly convenient, ARC solves most of the field pointer problems
    • Starting with iOS 9, some of the legacy of the system library wasassign(unsafe_unretain)Modification of thedelegateandtarget-actionThis was changed to weak, and when memory was reclaimed, these Pointers were set to nil, which greatly reduced the number of wild Pointers.
  • At present, most apps start from iOS 9, and the wild pointer is much less, but there are still wild pointer problems in the project, the essence is improper use of memory;

  • Mach exceptions are mostly wild Pointers. The most common examples in crash logs are objc_msgSend and unrecognized Selector sent to.

  • Zombie Object is a Zombie Object that hooks the dealloc method of the Object and zombified the Object by calling its own __dealloc_zombie method. When the object receives the message again,objc_msgsend, abort() is called and prints out the called method.

After iOS 9, NSNotificationCenter does not need to manually remove an observer

  • Before iOS9, the notification center uses unsafe_unretained modification to reference the observer. If the observer is reclaimed and not manually removed, the pointer points to the reclaimed memory area and becomes a wild pointer. If a message is sent again, Crash occurs.
  • After iOS 9, the notification center uses weak to modify and reference the observer. Even if the observer is not manually removed, the weak pointer will automatically set nil after the observer is reclaimed. And then you send a message, and you don’t have a problem.

5. IOS 10 nano_free Crash

  • In iOS 10.0-10.1, the Apple bug introduced the issue of nano_free crashes, which occur in nano zones within libsystem_malloc.dylib;

  • There are two implementations of memory management in libsystem_malloc.dylib: Nano zone and Scalable Zone. They manage memory blocks of different sizes:

    • Memory allocation functions such as malloc and calloc use nano_zone by default. Nao_zone is the allocation of memory smaller than 256B.
    • Scalable_zone is used when the value is larger than 256B.
  • At that time, the wechat team proposed several solutions, the final solution is not to use nano Zone, detailed description

    • Create your own zone and name itguard zone.
    • Modify the nano Zone function pointer to redirect to Guard Zone (throughmalloc_zone_createCreated).
      • For functions that do not pass a pointer, redirect directly to the Guard Zone
      • For functions with passed Pointers, size is used to determine the zone to which the function belongs before distribution.
  • More:

    • IOS 10 Nano_Free Crash
    • Libsystem_malloc dylib source code

6

  • Troubleshooting memory problems is difficult and complex. A deeper understanding of inner beings is needed
  • To avoid memory problems: fundamentally optimize memory usage, mainly in the following aspects: reduce large memory usage, reduce memory peak, avoid memory leaks, and deal with memory warnings;

Optimize memory usage

1. Reduce image decoding and rendering overhead

  • To render a picture on the screen, you need to decode it into a bitmap; And bitmap size:Pixel height * pixel width * 4 bytes(Four bytes for each pixel, four channels); Image decoding will increase memory usage, especially high resolution image decoding may cause memory explosion.
  • Code optimization Recommendations:
    • Treat “big” figure (bitmap size greater than 60 MB) decoding: original cutting into multiple insets, then mapped to the destination bitmap context in turn, concrete SDWebImage neutralization decodedAndScaledDownImageWithImage: about * * * * the implementation;

    • Limit the number of concurrent decoding images;

      • The image size should be adjusted as the display size to avoid resampling (resampling also consumes resources. Enlarged images are called upsamping and reduced to downsampling).
      • Use ImageIO to read image size and metadata information directly, reducing memory overhead.
      • IOS10 after useUIGraphicsImageRendererCreate an image context instead ofUIGraphicsBeginImageContextWithOptions, because the former is better, more efficient, and supports a wide color gamut;

2, other ways to reduce peak memory

  • Use AutoRealsepool properly to reduce memory spikes and avoid OOM

    • Based on reference counting, the drain method for a Pool releases all autoRelease objects in the Pool
    • You can nest more than one AutoReleasePool
    • AutoReleasePool is not set by default for each thread and needs to be created manually to avoid memory leaks
    • Nesting AutoReleasePool in a section of code that allocates memory frequently helps reduce overall memory spikes
  • Reuse large memory objects, such as UITableViewCell objects; Lazy loading of large memory objects

  • Options for imageNamed and imageWithContentOfFile

    • ImageNamed uses the system cache and is suitable for small images that are used frequently
    • ImageWithContentOfFile has no caching mechanism and is suitable for large images, which are released as soon as they are used
  • NSData is recommended to read files

    • It is recommended to use[NSData dataWithContentsOfFile:path options:NSDataReadingMappedIfSafe error:&error];
    • This API maps files to virtual memory and only reads the contents of the corresponding page into the physical memory page when the operation is performed.
  • Use NSCache instead of NSMutableDictionary, because NSCache cleans up memory automatically and makes more sense when memory is tight.

    • NSCache has two limits :totalCostLimt and countLimit. After these two limits are exceeded, the system will release some old resources.
    • Remove all caches after listening for memory warning messages
  • NSPurgableData is used instead of NSData for the following reasons:

    • It is automatically removed when the system is running low on memory
    • Applicable to big data
  • Stack memory allocation: alloca(size_t)

    • Stack allocation only modifies the stack pointer register, much faster than malloc iterates through and modifies the free list
    • Stack memory is usually already in physical memory, so you don’t have to worry about page errors
    • The space allocated by the stack is automatically freed when the function returns
    • But only suitable for small space allocation, and function nesting should not be too deep
  • Heap memory allocation: Calloc VS Malloc + memset

    • calloc(size_t num,size_t size)Memory is allocated as virtual memory, and the mapping of physical pages occurs only when it is accessed.
    • malloc + memsetWill produceDirty Memory
    • callocFunction to get the memory space is initialized, its contents are 0, andmallocThe memory obtained by the memset function is uninitialized and must be initialized using the memset function.

3. Avoid circular references and reduce memory leaks

  • Code optimization Recommendations
    • Declare the delegate as weak;
    • useweak strong danceTo solve the problem of circular references in blocks;
    • Implement the subclass of NSProxy(virtual class), and then define the weak modified target in the subclass, and then implement the message forwarding method, make target handle the business logic; Generally used to solve NSTimer, CADisplayLink circular reference;
    • Memory allocation for CoreFoundation objects, CoreGraphics objects, and C/C++ needs to be managed. Malloc requires free
  • Make good use of tools: MLeaksFinder + Instrument or FBMemoryProfiler + Instrument. Through the MLeaksFinder/FBMemoryProfiler discovered. Then use Instrument to verify;

4. Handle memory warnings

  • When Warning, release as many resources as possible, especially images that occupy a large amount of Memory, and rebuild them when needed.
  • In Memory Warning, some singletons can be freed.
  • Self. view = nil: After iOS 6, CALayer’s CABackingStore object (bitmap content) will be automatically discarded when the system issues a Memory Warning. UIView and CALayer classes are not reclaimed, but most of the memory is reclaimed, which is rebuilt by calling UIView’s drawRect: method when a Bitmap class is needed.
  • It is still best practice to reduce large memory usage, reduce memory spikes, and avoid memory leaks.

Article history

I’ve fixed some memory problems before

  • OC object memory notes

  • OOM problem notes

Before the picture decoding and picture optimization of some summary

  • Chapter 1: SDWebImage source code look at the image decoding
  • IOS Record 17: Optimized display of network pictures
  • Picture decoding notes

Refer to the article

Learn more about OOM in iOS

WWDC 2018: An in-depth look at iOS memory

Performance problems caused by page fault

IOS wechat memory monitoring

Summary of iOS wild pointer location

Memory management in iOS

Research on iOS memory management

Linux memory management, and the concept of Page faults

IOS memory management and malloc source code interpretation

Initialization of libmalloc source code analysis