Catch up on stories from the past week (and beyond) at the Slashdot story archive

 



Forgot your password?
typodupeerror
×
OS X Programming

How Snow Leopard Cut ObjC Launch Time In Half 158

MBCook writes "Greg Parker has an excellent technical article on his blog about the changes to the dynamic linker (dyld) for Objective-C that Snow Leopard uses to cut launch time in half and cut about 1/2 MB of memory per application. '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.' He also has a post on the new thread-local garbage collection that Snow Leopard uses for Objective-C."
This discussion has been archived. No new comments can be posted.

How Snow Leopard Cut ObjC Launch Time In Half

Comments Filter:
  • by Anonymous Coward on Sunday September 06, 2009 @10:43AM (#29331327)

    Or the GAC [wikipedia.org]

  • by BorgDrone ( 64343 ) on Sunday September 06, 2009 @10:44AM (#29331345) Homepage

    Did you even read the article ? Suppose not... this is slashdot after all.

    The article states that prebinding (similar to prelink) was used in previous versions of OS X and has been replaced by a much faster shared cache.

  • by bhima ( 46039 ) * <(Bhima.Pandava) (at) (gmail.com)> on Sunday September 06, 2009 @11:05AM (#29331471) Journal

    no. we've had a variant but lesser hell for years. Which has led to a series of cargo cult like maintenance procedures for Mac OS.

  • by lysergic.acid ( 845423 ) on Sunday September 06, 2009 @11:22AM (#29331579) Homepage

    Well, the FP is claiming that they're the same thing, and your post seemed to be agreeing with him. But yea, that troll rating probably should have gone to the post you replied to.

    I don't know anything about prelink, but Superfetch sounds completely different from dyld. Superfetch keeps frequently launched applications in memory to make them launch faster (much like Winamp Agent does for Winamp). dyld, OTOH, shortens application launch times by not reloading a shared library each time an application is launched. Keeping the shared library loaded in a shared cache also reduces the number of copies of that library you need loaded in memory. It doesn't sound like Superfetch does that.

    Both a turbocharger and a cold air intake can improve car performance, but that doesn't make them the same thing.

  • by Ma8thew ( 861741 ) on Sunday September 06, 2009 @11:24AM (#29331601)
    Objective-C is not equivalent to Cocoa. Cocoa is a set of frameworks written in Obj-C and primarily used by Obj-C programs.
  • by Anonymous Coward on Sunday September 06, 2009 @11:29AM (#29331637)

    The shared libs are shared. What was not shared before is the linking table, that must be built for accessing that shared code. prelink precalculates that table, and this apple thing does more or less the same.

  • by plsuh ( 129598 ) <plsuh@noSpAM.goodeast.com> on Sunday September 06, 2009 @11:51AM (#29331795) Homepage

    Moderators, please mod the parent down -- it completely misses the point.

    Objective-C selector uniquing caching is NOT the same as Windows Superfetch.

    Objective-C uses a two-phase dispatch for method calls. When you see a call in the Objective-C source code that looks like:

    [myObject init];

    the dispatch system:

    1. Looks up the function pointer for the method "init" in a table.
    2. Calls the "init" function via the function pointer.

    The problem arises in the method dispatch table when you have multiple methods named "init" -- which is very common. When an application is loaded the dynamic loader ("dyld") needs to separately identify all of the methods named "init" (and any other methods with conflicting names) that apply to different classes. This is done by "tagging" each method in the dispatch table, a process called selector uniquing.

    Now, this has to be not only for the application binary itself, but also for any Objective-C classes in shared libraries that are loaded. Almost all apps on Mac OS X load the libobjc.dylib library, which is cached to improve performance. As a part of the caching process, Snow Leopard now does the selector uniquing only once, and then stores the uniqued selectors in the cache. Thus, any application that links against libobjc.dylib (or any other library that is in the cache) only has to unique its own selectors, not those of the library as well. This significantly reduces the amount of overhead for launching an application compared to previous versions of Mac OS X.

    This process does not attempt to retain application binary code in memory in the face of page-outs as Superfetch does. Selector uniquing caching speeds application launch times by reducing the amount of computation that has to happen at launch, not by pre-loading the application's binary.

    Thread-local garbage collection is NOT the same as Windows Superfetch.

    Thread-local garbage collection is a third phase of garbage collection added on top of the Objective-C 2.0 garbage collection system, which speeds up the garbage collection system even further. By concentrating GC to what has occurred in a single thread, the GC system can delay and reduce the cost of a slow global sweep even beyond the generational GC algorithm.

    Windows Superfetch is a response to poorly written software.

    To quote from the Wikipedia article:

    The intent is to improve performance in situations where running an anti-virus scan or back-up utility would result in otherwise recently-used information being paged out to disk, or disposed from in-memory caches, resulting in lengthy delays when a user comes back to their computer after a period of non-use.

    In my opinion as an experienced application developer the user should never run into the problem that Superfetch attempts to solve. Anti-malware scans or backups are generally limited by I/O transfer rates, not by CPU. In such situations, using lots of memory to pre-load data makes no sense. It is relatively easy to write a two-buffer, threaded, streaming system for situations that are constrained by disk transfer rates without consuming scads of memory.

    In the bigger picture, Superfetch attempts to learn the times of day when apps are used and pre-loads their binaries. This is a nice concept, but I have serious doubts as to how useful it really is. The penalty for guessing wrong is fairly high, and users are more tolerant of consistent small slowdowns than they are of occasional long hangs (see the Mac literature on the spinning beach ball).

    Mac OS X is less likely to need such anti-malware scans in the first place as the application binaries are now digitally signed by the developer. Any malware that attempts to insert itself into applications will run into problems. This is not to say that the Mac is immune -- I can think of a number of holes that could be exploited (such as the fact that unsigned binaries w

  • by Creepy ( 93888 ) on Sunday September 06, 2009 @11:52AM (#29331809) Journal

    For reference, normally when a program is launched without prebinding, the program has to look into the symbol table for the shared library and "bind" it (basically, tell the program where it is). Prebinding basically does that in advance and saves the lookup table, but any time the library is changed, the bindings have to be regenerated.

        The article says prebinding is actually quite efficient for C/C++ code, but objective-C (used by macOS X and iPhone) is structured more like Smalltalk or Java, and uses selectors, which I believe can't be prebound (for you java programmers, these are equivalent to interfaces - C/C++ does not have this concept and instead allows direct access to the classes using protected or public) to interface into classes and these are instanced once for every application accessing that shared library. According to TFA, by keeping a single cached copy of the selector, they avoid the memory overhead of keeping individual copies. Since the OS itself has over 30000 selectors, you can imagine this cuts overhead by quite a bit, especially with commonly loaded libraries like Cocoa.

    For people comparing this to superfetch, it's not really the same thing - superfetch was pre-loading heavily used libraries into memory to avoid the delay in loading them during start time, and this is caching the library lookups onto disk that may or may not be memory resident at any particular time.

  • by malevolentjelly ( 1057140 ) on Sunday September 06, 2009 @12:09PM (#29331939) Journal

    It's nothing like Superfetch. Superfetch preloads applications into system memory [microsoft.com] and this shared cache doesn't do that instead from what I understand it preforms some of the work the linker would do on load in advance.

    The whole dyld sounds a lot like some of the basic features of the .NET runtime...

    Or maybe some of the features in this advanced futuristic os:

    http://blogs.technet.com/askperf/archive/2008/02/06/ws2008-dynamic-link-library-loader-and-address-space-load-randomization.aspx [technet.com]

  • by TheRaven64 ( 641858 ) on Sunday September 06, 2009 @01:23PM (#29332517) Journal

    selectors, which I believe can't be prebound (for you java programmers, these are equivalent to interfaces - C/C++ does not have this concept and instead allows direct access to the classes using protected or public)

    I'm sorry, but this and most of the rest of your description is completely wrong. Selectors are nothing like Java interfaces. Interfaces are Java's version of Objective-C Protocols. Selectors are abstract method names (Smalltalk calls them symbols). Each Objective-C class has some data structure mapping these to function pointers. When you send a message (call a method) you look up the function pointer corresponding to the selector in the receiving class. To make this fast, all selector comparisons are done as pointer comparisons. To make this work, the runtime needs to make sure that selectors are unique. This process involves building a large hash table and inserting every selector referenced by every compilation unit into it. By making the linker handle this uniquing, you have several advantages. The first is that the resulting table can be shared more easily between processes, resulting in a memory efficiency gain. The second is that the runtime can first try doing pointer comparison when registering a new selector, and only use the hash if the linker didn't unique the selector.

  • Re:enough fucking (Score:3, Informative)

    by Jesus_666 ( 702802 ) on Sunday September 06, 2009 @04:44PM (#29334155)
    You are reading apple.slashdot.org. It might have occurred to you that at this subdomain you might find stories about Apple? You can filter it out, you know.
  • by Jimithing DMB ( 29796 ) <dfe@tg[ ].org ['wbd' in gap]> on Monday September 07, 2009 @12:38PM (#29341421) Homepage

    selectors, which I believe can't be prebound (for you java programmers, these are equivalent to interfaces - C/C++ does not have this concept and instead allows direct access to the classes using protected or public)

    I'm sorry, but this and most of the rest of your description is completely wrong. Selectors are nothing like Java interfaces. Interfaces are Java's version of Objective-C Protocols. Selectors are abstract method names (Smalltalk calls them symbols). Each Objective-C class has some data structure mapping these to function pointers.

    Although I will agree with you that GPP is somewhat misinformed I take issue with your statement that selectors are nothing like Java Interfaces.

    It is true that the class structure of Objective-C (one root NSObject class, at least in common practice) and the class structure of Java (one root Object class) are virtually identical. And it is true that an Objective-C protocol has feature parity with a Java Interface and when you think of formal interfaces in Java the equivalent to that in Objective-C is a protocol.

    So Java has anObj instanceof SomeClass which will indicate that anObj is an instance of SomeClass or an instance of some other class that derives from SomeClass. The Objective-C equivalent to this is [anObj isKindOfClass:[SomeClass class]]. And Java has anObj instanceof SomeInterface where the equivalent in Objective-C is [anObj conformsToProtocol:@protocol(SomeInterface)].

    But then Objective-C also has this nifty thing [anObj respondsToSelector:@selector(doSomething:)] which does exactly what it says and allows you to see if the object will respond to the doSomething selector that takes one argument. Java has no analogue to this. I mean, you can sort of fake it using reflection to find methods but it isn't quite the same thing.

    The bottom line is that when a unique selector can be looked up like this each selector functions almost as if it were its own Java-style interface. There is clearly a parallel between Java if(anObj instanceof DoSomethingInterface) ((DoSomethingInterface)anObj).doSometing(1); and Objective-C if([anObj respondsToSelector:@selector(doSomething:)]) [(id)anObj doSomething: 1];

    From a coding standpoint where I would think to use a respondsToSelector: in Objective-C I wind up making an interface containing exactly 1 method in Java. Sometimes it's the right choice to add the extra lines and make an interface (and if so, then you should add all the extra lines and make a protocol in Objective-C). But often times I find the required formality of Java to be a distraction.

"May your future be limited only by your dreams." -- Christa McAuliffe

Working...