Selector uniquing in the dyld shared cache

转载 2015年11月19日 16:39:56

因为在阅读英文版教材时遇到了几个术语,不太理解,然后就转载了下。

Mac OS X Snow Leopard cuts in half the launch-time overhead of starting the Objective-C runtime, and simultaneously saves a few hundred KB of memory per app. This comes for free to every app, courtesy of one of the few pieces of Mac OS X that lives below even the Objective-C runtime: dyld.

一.dyld and the shared cache

dyld is the dynamic loader and linker. When your process starts, dyld loads your executable and its shared libraries into memory, links the cross-library C function and variable references together, and starts execution on its way towards main().

In theory a shared library could be different every time your program is run. In practice, you get the same version of the shared libraries almost every time you run, and so does every other process on the system. The system takes advantage of this by building the dyld shared cache. The shared cache contains a copy of many system libraries, with most of dyld’s linking and loading work done in advance. Every process can then share that shared cache, saving memory and launch time.

(Incidentally, the shared cache beats the pants off the pre-Leopard prebinding system that was supposed to achieve the same optimizations. Remember the post-install “Optimizing System Performance” step that often took longer than the install itself? That was prebinding being updated. Rebuilding the shared cache is so blazingly fast that the installer doesn’t bother to report it anymore.)

二.Objective-C selector uniquing

Leopard’s dyld shared cache is great for C code, but it didn’t do anything to help Objective-C’s startup overhead. The single biggest launch cost for Objective-C is selector uniquing. The app and every shared library contain their own copies of selector names like “alloc” and “init”. The runtime needs to choose a single canonical SEL pointer value for each selector name, and then update the metadata for every call site and method list to use the blessed unique value. This means building a big hash table (memory), calling strcmp() a lot (time), and modifying copy-on-write metadata (more memory).

There are tens of thousands of unique selectors present in a typical process. If you run strings /usr/lib/libobjc.dylib on Leopard you can see the thirty-thousand-line built-in selector table that was a previous attempt to reduce the memory cost. Even so the cost goes up with every new class and method added to Cocoa.framework; left unchecked, an identical app would take longer to launch and use more memory after every OS upgrade.

The obvious solution? Do the work of selector uniquing in the dyld shared cache. Build a selector table into the shared cache itself, and update the selector references in the cached copy of the shared libraries. Then you save memory because every process shares the same selector table, and save time because the runtime does not need to rebuild it during every app launch. The runtime only needs to fix the selector references from the app itself. The catch? Selectors are too dynamic to be implemented as C symbols, so the shared cache construction tool needed to be taught how to read and write Objective-C’s metadata.

三.Optimization WIN

Snow Leopard’s dyld shared cache uniques Objective-C selectors, and Snow Leopard’s Objective-C runtime recognizes when the selectors in a shared library are already uniqued courtesy of the shared cache. About half of the runtime’s initialization time is eliminated, making warm app launch several tenths of a second faster. Typical memory savings is 200-500 KB per process, adding up to a few megabytes system-wide. When this optimization ships on the iPhone OS side, it’s estimated to save 1 MB on a 128 MB device. The iPhone performance team would pay any number of arms and legs for that kind of gain.

You can watch the system in action with various debugging flags.

$ sudo /usr/bin/update_dyld_shared_cache -debug -verify
[…]
update_dyld_shared_cache: for x86_64, uniquing objc selectors
update_dyld_shared_cache: for x86_64, found 68761 unique objc selectors
update_dyld_shared_cache: for x86_64, 541736/590908 bytes (91%) used in libobjc unique selector section
update_dyld_shared_cache: for x86_64, updated 205230 selector references

$ OBJC_PRINT_PREOPTIMIZATION=YES /usr/bin/defaults
objc[424]: PREOPTIMIZATION: selector preoptimization ENABLED (version 3)
objc[424]: PREOPTIMIZATION: honoring preoptimized selectors in /usr/lib/libobjc.A.dylib
objc[424]: PREOPTIMIZATION: honoring preoptimized selectors in /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation
objc[424]: PREOPTIMIZATION: honoring preoptimized selectors in /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/Metadata.framework/Versions/A/Metadata
objc[424]: PREOPTIMIZATION: honoring preoptimized selectors in /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation

You can estimate the memory savings with the allmemory tool. Record post-launch memory usage of an app run with and without environment variable OBJC_DISABLE_PREOPTIMIZATION=YES. Look for the count of dirty pages; each dirty page is 4 KB eaten by that process. With 64-bit TextEdit I see the dirty page count jump from 725 to 1069 after disabling the optimization. This is an overestimate - many of those pages would have been not-dirty in Leopard because of the old built-in selector table - but it does show the magnitude of the win.

The Objective-C runtime does more than just selector uniquing during launch. Future improvements to the dyld shared cache may precompute some of that other work, to further improve launch time, save memory, and reduce the cost of linking to Objective-C code that you don’t actually use. But selector uniquing as seen in Snow Leopard is by far the biggest bang for the buck.

原网页:http://www.sealiesoftware.com/blog

如何解iOS系统中系统库的dyld缓存

这几天想反汇编看一下iOS 9系统中安全框架的实现代码,于是找到系统中的“/System/Library/Frameworks/Security.framework/”目录,发现里面除了一些配置文件和...
  • Roland_Sun
  • Roland_Sun
  • 2015年12月28日 11:13
  • 2373

深入理解Oracle中的shared pool与library cache组件及相关等待事件

传统的’library cache pin’在10.2.0.2之后默认被取代, 此处PIN被Mutex及其ref count取代。 当进程执行游标语句时或者需要PIN,或者需要hard parse一个...
  • wanglha
  • wanglha
  • 2014年11月21日 11:09
  • 645

ehcache缓存初体验

  • qq_21989939
  • qq_21989939
  • 2015年08月24日 15:53
  • 449

iOS平台Dyld库函数遍历进程内的模块信息

iOS遍历进程模块信息 dyld.h 源码
  • HK_5788
  • HK_5788
  • 2016年09月24日 09:43
  • 1086

dyld源码分析-动态加载main的流程和load函数执行的流程

0x00 摘要 在OS X或者IOS上运行一个程序时,dyld除了需要加载主要的执行程序之外,还需要加载需要的库文件以及库文件依赖的库文件。 1 2 // instantiate I...
  • fishmai
  • fishmai
  • 2016年05月15日 22:28
  • 2225

XCode6添加自定义framework运行真机出现dyld: Library not loaded的解决方法

笔记下,bei
  • cooldragon
  • cooldragon
  • 2014年09月30日 17:25
  • 27549

ImageMagick的安装及使用

最近在使用ImageMagick处理酒店团购图片,写篇博客小小的总结下它的安装及用法。ImageMagick是一套功能强大且免费的图片处理开发包,可以用来读,写和处理多种格式的图片文件,总之很强大就是...
  • u012451979
  • u012451979
  • 2013年12月18日 10:55
  • 5110

ios应用加载第三方动态库dylib时崩溃及解决办法

最近在开发一个App需要以root权限运行,其中用到一个第三方合作开发的动态库。用theos创建工程,编译,打包,安装都没有问题,但是在手机上点击运行的时候崩溃,崩溃日志如下: {"bundleID"...
  • u010934582
  • u010934582
  • 2015年03月19日 12:41
  • 3227

探索Android中selector和shape的结合使用

Android中的Selector(背景选择器)主要是用来改变一个按钮控件的背景,在Android UI设计中经常会遇到,比如我们在点击Button时需要有些效果的变化,这时候就要用到和。和对美化控件...
  • qq_20785431
  • qq_20785431
  • 2015年12月06日 21:10
  • 8961

@selector的函数如何传参数/如何传递多个参数

不同的类会有不同的传递方式,参数名也不尽相同。如果是传单个参数的就不用集合,如果是传多个参数可以用类似nsarray,nsdictionary之类的集合传递。看下面例子: 例子1: 通过N...
  • u011862058
  • u011862058
  • 2016年07月07日 14:38
  • 1594
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Selector uniquing in the dyld shared cache
举报原因:
原因补充:

(最多只允许输入30个字)