Automatic Reference Counting (ARC) is a memory management feature of the Clangcompiler providing automatic reference counting for the Objective-C and Swiftprogramming languages. At compile time, it inserts into the object codemessages
retain and release [1][2] which increase and decrease the reference count at run time, marking for deallocation those objects when the number of references to them reaches zero.
ARC differs from tracing garbage collection in that there is no background process that deallocates the objects asynchronously at runtime.[3] Unlike tracing garbage collection, ARC does not handle reference cycles automatically. This means that as long as there are 'strong' references to an object, it will not be deallocated. Strong cross-references can accordingly create deadlocks and memory leaks. It is up to the developer to break cycles by using weak references.[4]
Responsive iOS and OS X applications with concurrency. Pro Multithreading and Memory Management for iOS and OS X shows you how ARC, Appleâs game-changing memory management system, works and how. Level: IntermediateâAdvanced www.apress. Com BOOKS FOR. Automatic Reference Counting (ARC) is a memory management feature of the Clang compiler providing automatic reference counting for the Objective-C and Swift programming languages.At compile time, it inserts into the object code messages retain and release which increase and decrease the reference count at run time, marking for deallocation those objects when the number of references to them.
Apple Inc. deploys ARC in their operating systems, such as macOS (OS X) and iOS. Limited support (ARCLite)[5] has been available since Mac OS X Snow Leopard and iOS 4, with complete support following in Mac OS XLion and iOS 5.[6] Garbage collection was declared deprecated in OS X Mountain Lion, in favor of ARC, and removed from the Objective-C runtime library in macOS Sierra.[7][8]
Objective-C[edit]
The following rules are enforced by the compiler when ARC is turned on:
Property declarations[edit]
ARC introduces some new property declaration attributes, some of which replace the old attributes.
Zeroing weak references[edit]
Zeroing weak references is a feature in Objective-C ARC that automatically clears (sets to
nil ) weak-reference local variables, instance variables, and declared properties immediately before the object being pointed to starts deallocating. This ensures that the pointer goes to either a valid object or nil , and avoids dangling pointers. Prior to the introduction of this feature, 'weak references' referred to references that were not retaining, but were not set to nil when the object they pointed to was deallocated (equivalent to unsafe_unretained in ARC), thus possibly leading to a dangling pointer. The programmer typically had to ensure that all possible weak references to an object were set to nil manually when it was being deallocated. Zeroing weak references obviates the need to do this.
Zeroing weak references are indicated by using the declared property attribute
weak or by using the variable attribute __weak .
Zeroing weak references are only available in Mac OS X Lion (10.7) or later and iOS 5 or later, because they require additional support from the Objective-C runtime. However, some OS X classes do not currently support weak references.[9] Code that uses ARC but needs to support versions of the OS older than those above cannot use zeroing weak references, and therefore must use
unsafe_unretained weak references. There exists a third-party library called PLWeakCompatibility [1] that allows one to use zeroing weak references even on these older OS versions.
Converting to[edit]
Xcode 4.2 or later provides a way to convert code to ARC.[10] As of Xcode 4.5, it is found by choosing Edit > Refactor > Convert to Objective-C ARC.. Although Xcode will automatically convert most code, some code may have to be converted manually. Xcode will inform the developer when more complex use cases arise, such as when a variable is declared inside an autorelease pool and used outside it or when two objects need to be toll-free bridged with special casts. How to scan for wireless networks in mac os x.
Swift[edit]
In Swift, references to objects are strong, unless they are declared
weak or unowned . Swift requires explicit handling of nil with the Optional type: a value type that can either have a value or be nil. An Optional type must be handled by 'unwrapping' it with a conditional statement, allowing safe usage of the value, if present. Conversely, any non-Optional type will always have a value and cannot be nil.
Accordingly, a strong reference to an object cannot be of type Optional, as the object will be kept in the heap until the reference itself is deallocated. A weak reference is of type Optional, as the object can be deallocated and the reference be set to nil. Unowned references fall in-between; they are neither strong nor of type Optional. Instead, the compiler assumes that the object to which an unowned reference points is not deallocated as long the reference itself remains allocated. This is typically used in situations where the target object itself holds a reference to the object that holds the unowned reference.
Swift also differs from Objective-C in its usage and encouragement of value types instead of reference types. Most types in the Swift standard library are value types and they are copied by value, whereas classes and closures are reference types and passed by reference. Because value types are copied when passed around, they are deallocated automatically with the reference that created them.[11]
See also[edit]References[edit]
External links[edit]
Retrieved from 'https://en.wikipedia.org/w/index.php?title=Automatic_Reference_Counting&oldid=952805586'
For many years, maximum computer performance was limited largely by the speed of a single microprocessor at the heart of the computer. As the speed of individual processors started reaching their practical limits, however, chip makers switched to multicore designs, giving the computer the opportunity to perform multiple tasks simultaneously. And although OS X takes advantage of these cores whenever it can to perform system-related tasks, your own applications can also take advantage of them through threads.
What Are Threads?
Threads are a relatively lightweight way to implement multiple paths of execution inside of an application. At the system level, programs run side by side, with the system doling out execution time to each program based on its needs and the needs of other programs. Inside each program, however, exists one or more threads of execution, which can be used to perform different tasks simultaneously or in a nearly simultaneous manner. The system itself actually manages these threads of execution, scheduling them to run on the available cores and preemptively interrupting them as needed to allow other threads to run.
From a technical standpoint, a thread is a combination of the kernel-level and application-level data structures needed to manage the execution of code. https://spirefloor.weebly.com/bootable-mac-os-x-usb-for-pc.html. The kernel-level structures coordinate the dispatching of events to the thread and the preemptive scheduling of the thread on one of the available cores. The application-level structures include the call stack for storing function calls and the structures the application needs to manage and manipulate the threadâs attributes and state.
In a non-concurrent application, there is only one thread of execution. That thread starts and ends with your applicationâs
main routine and branches one-by-one to different methods or functions to implement the applicationâs overall behavior. By contrast, an application that supports concurrency starts with one thread and adds more as needed to create additional execution paths. Each new path has its own custom start routine that runs independently of the code in the applicationâs main routine. Having multiple threads in an application provides two very important potential advantages:
If your application has only one thread, that one thread must do everything. It must respond to events, update your applicationâs windows, and perform all of the computations needed to implement your applicationâs behavior. The problem with having just one thread is that it can only do one thing at a time. So what happens when one of your computations takes a long time to finish? While your code is busy computing the values it needs, your application stops responding to user events and updating its windows. If this behavior continues long enough, a user might think your application is hung and try to forcibly quit it. If you moved your custom computations onto a separate thread, however, your applicationâs main thread would be free to respond to user interactions in a more timely manner.
With multicore computers common these days, threads provide a way to increase performance in some types of applications. Threads that perform different tasks can do so simultaneously on different processor cores, making it possible for an application to increase the amount of work it does in a given amount of time.
Of course, threads are not a panacea for fixing an applicationâs performance problems. Along with the benefits offered by threads come the potential problems. Having multiple paths of execution in an application can add a considerable amount of complexity to your code. Each thread has to coordinate its actions with other threads to prevent it from corrupting the applicationâs state information. Because threads in a single application share the same memory space, they have access to all of the same data structures. If two threads try to manipulate the same data structure at the same time, one thread might overwrite anotherâs changes in a way that corrupts the resulting data structure. Even with proper protections in place, you still have to watch out for compiler optimizations that introduce subtle (and not so subtle) bugs into your code.
Threading Terminology
Before getting too far into discussions about threads and their supporting technologies, it is necessary to define some basic terminology.
If you are familiar with UNIX systems, you may find that the term âtaskâ is used differently by this document. On UNIX systems, the term âtaskâ is used at times to refer to a running process.
This document adopts the following terminology:
Alternatives to Threads
One problem with creating threads yourself is that they add uncertainty to your code. Threads are a relatively low-level and complicated way to support concurrency in your application. If you do not fully understand the implications of your design choices, you could easily encounter synchronization or timing issues, the severity of which can range from subtle behavioral changes to the crashing of your application and the corruption of the userâs data.
Another factor to consider is whether you need threads or concurrency at all. Threads solve the specific problem of how to execute multiple code paths concurrently inside the same process. There may be cases, though, where the amount of work you are doing does not warrant concurrency. Threads introduce a tremendous amount of overhead to your process, both in terms of memory consumption and CPU time. You may discover that this overhead is too great for the intended task, or that other options are easier to implement.
Table 1-1 lists some of the alternatives to threads. This table includes both replacement technologies for threads (such as operation objects and GCD) and alternatives that are geared towards efficiently using the single thread you already have.
Warning: When launching separate processes using the
fork function, you must always follow a call to fork with a call to exec or a similar function. Applications that depend on the Core Foundation, Cocoa, or Core Data frameworks (either explicitly or implicitly) must make a subsequent call to an exec function or those frameworks may behave improperly.
Pro Multithreading And Memory Management For Ios And Os X 10Threading Support
If you have existing code that uses threads, OS X and iOS provide several technologies for creating threads in your applications. In addition, both systems also provide support for managing and synchronizing the work that needs to be done on those threads. The following sections describe some of the key technologies that you need to be aware of when working with threads in OS X and iOS.
Threading Packages
Although the underlying implementation mechanism for threads is Mach threads, you rarely (if ever) work with threads at the Mach level. Instead, you usually use the more convenient POSIX API or one of its derivatives. The Mach implementation does provide the basic features of all threads, however, including the preemptive execution model and the ability to schedule threads so they are independent of each other.
Pro Multithreading And Memory Management For Ios And Os X 11
Listing 2-2 lists the threading technologies you can use in your applications.
At the application level, all threads behave in essentially the same way as on other platforms. After starting a thread, the thread runs in one of three main states: running, ready, or blocked. If a thread is not currently running, it is either blocked and waiting for input or it is ready to run but not scheduled to do so yet. The thread continues moving back and forth among these states until it finally exits and moves to the terminated state.
When you create a new thread, you must specify an entry-point function (or an entry-point method in the case of Cocoa threads) for that thread. This entry-point function constitutes the code you want to run on the thread. When the function returns, or when you terminate the thread explicitly, the thread stops permanently and is reclaimed by the system. Because threads are relatively expensive to create in terms of memory and time, it is therefore recommended that your entry point function do a significant amount of work or set up a run loop to allow for recurring work to be performed.
For more information about the available threading technologies and how to use them, see Thread Management.
Run Loops
A run loop is a piece of infrastructure used to manage events arriving asynchronously on a thread. A run loop works by monitoring one or more event sources for the thread. As events arrive, the system wakes up the thread and dispatches the events to the run loop, which then dispatches them to the handlers you specify. If no events are present and ready to be handled, the run loop puts the thread to sleep.
You are not required to use a run loop with any threads you create but doing so can provide a better experience for the user. Run loops make it possible to create long-lived threads that use a minimal amount of resources. Because a run loop puts its thread to sleep when there is nothing to do, it eliminates the need for polling, which wastes CPU cycles and prevents the processor itself from sleeping and saving power.
To configure a run loop, all you have to do is launch your thread, get a reference to the run loop object, install your event handlers, and tell the run loop to run. The infrastructure provided by OS X handles the configuration of the main threadâs run loop for you automatically. If you plan to create long-lived secondary threads, however, you must configure the run loop for those threads yourself.
Details about run loops and examples of how to use them are provided in Run Loops.
Synchronization Tools
One of the hazards of threaded programming is resource contention among multiple threads. If multiple threads try to use or modify the same resource at the same time, problems can occur. One way to alleviate the problem is to eliminate the shared resource altogether and make sure each thread has its own distinct set of resources on which to operate. When maintaining completely separate resources is not an option though, you may have to synchronize access to the resource using locks, conditions, atomic operations, and other techniques.
Locks provide a brute force form of protection for code that can be executed by only one thread at a time. The most common type of lock is mutual exclusion lock, also known as a mutex. When a thread tries to acquire a mutex that is currently held by another thread, it blocks until the lock is released by the other thread. Several system frameworks provide support for mutex locks, although they are all based on the same underlying technology. In addition, Cocoa provides several variants of the mutex lock to support different types of behavior, such as recursion. For more information about the available types of locks, see Locks.
In addition to locks, the system provides support for conditions, which ensure the proper sequencing of tasks within your application. A condition acts as a gatekeeper, blocking a given thread until the condition it represents becomes true. When that happens, the condition releases the thread and allows it to continue. The POSIX layer and Foundation framework both provide direct support for conditions. (If you use operation objects, you can configure dependencies among your operation objects to sequence the execution of tasks, which is very similar to the behavior offered by conditions.)
Although locks and conditions are very common in concurrent design, atomic operations are another way to protect and synchronize access to data. Atomic operations offer a lightweight alternative to locks in situations where you can perform mathematical or logical operations on scalar data types. Atomic operations use special hardware instructions to ensure that modifications to a variable are completed before other threads have a chance to access it.
For more information about the available synchronization tools, see Synchronization Tools.
Inter-thread Communication
Although a good design minimizes the amount of required communication, at some point, communication between threads becomes necessary. (A threadâs job is to do work for your application, but if the results of that job are never used, what good is it?) Threads may need to process new job requests or report their progress to your applicationâs main thread. In these situations, you need a way to get information from one thread to another. Fortunately, the fact that threads share the same process space means you have lots of options for communication.
There are many ways to communicate between threads, each with its own advantages and disadvantages. Configuring Thread-Local Storage lists the most common communication mechanisms you can use in OS X. (With the exception of message queues and Cocoa distributed objects, these technologies are also available in iOS.) The techniques in this table are listed in order of increasing complexity.
Design Tips
The following sections offer guidelines to help you implement threads in a way that ensures the correctness of your code. https://spirefloor.weebly.com/java-se-6-for-mac-os-x-yosemite.html. Some of these guidelines also offer tips for achieving better performance with your own threaded code. As with any performance tips, you should always gather relevant performance statistics before, during, and after you make changes to your code.
Avoid Creating Threads Explicitly
Writing thread-creation code manually is tedious and potentially error-prone and you should avoid it whenever possible. OS X and iOS provide implicit support for concurrency through other APIs. Rather than create a thread yourself, consider using asynchronous APIs, GCD, or operation objects to do the work. These technologies do the thread-related work behind the scenes for you and are guaranteed to do it correctly. In addition, technologies such as GCD and operation objects are designed to manage threads much more efficiently than your own code ever could by adjusting the number of active threads based on the current system load. For more information about GCD and operation objects, see Concurrency Programming Guide.
Keep Your Threads Reasonably Busy
If you decide to create and manage threads manually, remember that threads consume precious system resources. You should do your best to make sure that any tasks you assign to threads are reasonably long-lived and productive. At the same time, you should not be afraid to terminate threads that are spending most of their time idle. Threads use a nontrivial amount of memory, some of it wired, so releasing an idle thread not only helps reduce your applicationâs memory footprint, it also frees up more physical memory for other system processes to use.
Important: Before you start terminating idle threads, you should always record a set of baseline measurements of your applications current performance. After trying your changes, take additional measurements to verify that the changes are actually improving performance, rather than hurting it.
Avoid Shared Data Structures
The simplest and easiest way to avoid thread-related resource conflicts is to give each thread in your program its own copy of whatever data it needs. Parallel code works best when you minimize the communication and resource contention among your threads.
Creating a multithreaded application is hard. Even if you are very careful and lock shared data structures at all the right junctures in your code, your code may still be semantically unsafe. For example, your code could run into problems if it expected shared data structures to be modified in a specific order. Changing your code to a transaction-based model to compensate could subsequently negate the performance advantage of having multiple threads. Eliminating the resource contention in the first place often results in a simpler design with excellent performance.
![]() Threads and Your User Interface
If your application has a graphical user interface, it is recommended that you receive user-related events and initiate interface updates from your applicationâs main thread. This approach helps avoid synchronization issues associated with handling user events and drawing window content. Some frameworks, such as Cocoa, generally require this behavior, but even for those that do not, keeping this behavior on the main thread has the advantage of simplifying the logic for managing your user interface.
There are a few notable exceptions where it is advantageous to perform graphical operations from other threads. For example, you can use secondary threads to create and process images and perform other image-related calculations. Using secondary threads for these operations can greatly increase performance. If you are not sure about a particular graphical operation though, plan on doing it from your main thread.
For more information about Cocoa thread safety, see Thread Safety Summary. For more information about drawing in Cocoa, see Cocoa Drawing Guide.
Be Aware of Thread Behaviors at Quit Time
A process runs until all non-detached threads have exited. By default, only the applicationâs main thread is created as non-detached, but you can create other threads that way as well. When the user quits an application, it is usually considered appropriate behavior to terminate all detached threads immediately, because the work done by detached threads is considered optional. If your application is using background threads to save data to disk or do other critical work, however, you may want to create those threads as non-detached to prevent the loss of data when the application exits.
Creating threads as non-detached (also known as joinable) requires extra work on your part. Because most high-level thread technologies do not create joinable threads by default, you may have to use the POSIX API to create your thread. In addition, you must add code to your applicationâs main thread to join with the non-detached threads when they do finally exit. For information on creating joinable threads, see Setting the Detached State of a Thread.
If you are writing a Cocoa application, you can also use the
applicationShouldTerminate: delegate method to delay the termination of the application until a later time or cancel it altogether. When delaying termination, your application would need to wait until any critical threads have finished their tasks and then invoke the replyToApplicationShouldTerminate: method. For more information on these methods, see NSApplication Class Reference.
Handle ExceptionsPro Multithreading And Memory Management For Ios And Os X 7
Exception handling mechanisms rely on the current call stack to perform any necessary clean up when an exception is thrown. Because each thread has its own call stack, each thread is therefore responsible for catching its own exceptions. Failing to catch an exception in a secondary thread is the same as failing to catch an exception in your main thread: the owning process is terminated. You cannot throw an uncaught exception to a different thread for processing.
If you need to notify another thread (such as the main thread) of an exceptional situation in the current thread, you should catch the exception and simply send a message to the other thread indicating what happened. Depending on your model and what you are trying to do, the thread that caught the exception can then continue processing (if that is possible), wait for instructions, or simply exit.
Note: In Cocoa, an
NSException object is a self-contained object that can be passed from thread to thread once it has been caught.
In some cases, an exception handler may be created for you automatically. For example, the
@synchronized directive in Objective-C contains an implicit exception handler.
Terminate Your Threads Cleanly
The best way for a thread to exit is naturally, by letting it reach the end of its main entry point routine. Although there are functions to terminate threads immediately, those functions should be used only as a last resort. Terminating a thread before it has reached its natural end point prevents the thread from cleaning up after itself. If the thread has allocated memory, opened a file, or acquired other types of resources, your code may be unable to reclaim those resources, resulting in memory leaks or other potential problems.
For more information on the proper way to exit a thread, see Terminating a Thread.
Thread Safety in Libraries
Although an application developer has control over whether an application executes with multiple threads, library developers do not. When developing libraries, you must assume that the calling application is multithreaded or could switch to being multithreaded at any time. As a result, you should always use locks for critical sections of code.
For library developers, it is unwise to create locks only when an application becomes multithreaded. If you need to lock your code at some point, create the lock object early in the use of your library, preferably in some sort of explicit call to initialize the library. Although you could also use a static library initialization function to create such locks, try to do so only when there is no other way. Execution of an initialization function adds to the time required to load your library and could adversely affect performance.
Note: Always remember to balance calls to lock and unlock a mutex lock within your library. You should also remember to lock library data structures rather than rely on the calling code to provide a thread-safe environment.
If you are developing a Cocoa library, you can register as an observer for the
NSWillBecomeMultiThreadedNotification if you want to be notified when the application becomes multithreaded. You should not rely on receiving this notification, though, as it might be dispatched before your library code is ever called.
Pro Multithreading And Memory Management For Ios And Os X DownloadPro Multithreading And Memory Management For Ios And Os X 8
Copyright © 2014 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2014-07-15
Comments are closed.
|
AuthorWrite something about yourself. No need to be fancy, just an overview. Archives
December 2020
Categories |