一篇很好的关于View&CALayer内存优化原理的文字
2014-08-26 15:46
197 查看
View Controller Lifecycle in iOS 6
by thejoeconwayblog
Some of you may have noticed that your view controllers no longer get sent viewWillUnload or viewDidUnload in iOS 6. That’s because your view controllers don’t automatically unload their views anymore.Your first thought may be, “Ok, well how do I manually unload my views on a low memory warning? This seems like a step backwards.”
Then you go searching for an answer, and you come up with this:
- (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; if([self isViewLoaded] && ![[self view] window]) { [self setView:nil]; } }
However, this is both unnecessary and potentially harmful because of some changes to the underlying support for UIViews. Therefore, in practice, you rarely need to unload a view controller’s view during a low memory warning. (And in theory, you will never have
to.)
But why? If you’ve read our entire iOS programming book, you’ve gained the knowledge that a UIView is a subclass of UIResponder (so that it can receive events) and has a pointer to its own CALayer instance (so that it can be drawn on the screen).
A CALayer is a container for a bitmap image. When a UIView runs its drawRect: method, it is creating the bitmap image for its layer. The rest of a layer’s instance variables (many of which it borrows from its UIView, like its frame and backgroundColor) indicate
how and where that bitmap image is composited onto the screen.
But the biggest part of the layer (in terms of memory usage) is that bitmap. A layer itself is only 48 bytes and a standard UIView is only 96 bytes, regardless of their size on the screen. The memory consumption for a layer’s bitmap, however, grows very large
depending on the bounds of the layer. For example, a full screen retina-display iPad view can be up to a whopping 12 megabytes.
The approach taken by iOS 6 is that a low memory warning should only destroy the layer’s bitmap, but keep the CALayer and UIView objects intact. This makes sense given the memory consumption of the view and layer are relatively small compared to the bitmap.
Additionally, a bitmap can be redrawn by having the view run drawRect: again, so it is not like we’ve lost anything.
In fact, something is gained by this approach: your controller no longer needs to re-populate view content after a low memory warning. For example, consider a view controller that maintained a couple of text fields. If that view controller’s view were to go
off screen and a low memory warning were to occur, the view controller must save the text currently in those text fields and repopulate them in viewDidLoad or viewWillAppear:. This is no longer an issue because the text fields are never destroyed, thus they
retain their text for when the text field’s bitmap is drawn again. This simplifies a very error-prone section of UIViewController code.
There are some additional smarts built into this process of dumping the layer’s bitmap image that are really cool. First, let’s make sure we understand allocation and deallocation. When a memory is allocated (an object, a bitmap, whatever), an appropriately
sized chunk of memory from the heap is marked as “in use” and a pointer to the beginning of that chunk of memory is returned. In the case of an object allocation, we think of that pointer as “the object” but really, it’s just the address of a chunk of “in
use” memory.
While a chunk of memory is allocated (“in use”), there are guards that prevent code from using that memory unless it is accessed by going through the pointer that was returned during allocation. In a sense, that memory is safe from being screwed with unless
you intend to screw with it.
Deallocation simply removes those guards and marks that chunk of memory as “not in use”. This means that the next time you allocate an object, you can use some or all of that “not in use” memory to form a new allocation. Upon deallocation, the values stored
in that chunk of memory do not change. While it is possible to access that deallocated memory again and it may be the same, chances are that the memory has changed in some way. Therefore, it’s never safe to access deallocated memory through the pointer you
were given upon allocation.
Now, on to why this matters for views and their layers. Each layer has a contents property that points to an object that represents the layer’s bitmap. The type of this object is a private, opaque class named CABackingStore, which contains the actual bitmap
as well as some metadata (like whether or not the image has an alpha channel and how many bytes per pixel are used). Thus, it is the CABackingStore that needs to be destroyed when memory is running low.
However, the neat trick here is that a low memory warning does not destroy a CABackingStore. Instead, if a view is offscreen during a low memory warning, its layer’s CABackingStore is set to “volatile”. The volatile flag (which is not the same as the volatile
keyword in C), in this context, is like deallocation in the sense that it allows the memory of the CABackingStore to be allocated for a different purpose. The difference between marking this memory as volatile and deallocating it is that the volatile memory
can actually be reclaimed; it is not lost forever.
Consider why this is such an interesting optimization. If a view (more accurately, its layer) were to destroy its backing store, the next time the view went on screen it would have to recreate that backing store by running drawRect:. drawRect: is an expensive
call, so avoiding it is very important. By allowing the backing store to be reclaimed, the layer can avoid having its UIView execute drawRect: again.
Of course, it is possible that some time between when the backing store was marked as volatile and the view that owned it goes back on the screen, the memory for that backing store was reallocated for a different purpose. In that case, the view would have to
run its drawRect: method again to produce its bitmap.
from:http://thejoeconwayblog.wordpress.com/2012/10/04/view-controller-lifecycle-in-ios-6/
相关文章推荐
- 关于CircleImageView使用和分析很好的一篇文章
- 关于extern "C"的一篇很好的文章
- 转一篇写得很好的关于iptables原理和流程的文章
- 转一篇写得很好的关于iptables原理和流程的文章
- 关于type="submit"默认文字问题
- 上一篇随笔<深入剖析ASP.NET组件设计>一书中第三章关于ASP.NET运行原理的补白
- 关于PJSIP介绍的的一篇很好的文章
- 新年伊始,转一篇很好的关于职业规划方面的文章
- 关于GridBagLayout网络上一篇很好的文章
- [收藏]一篇讲述ASP.NET运行原理的很好的文章
- 关于Action&View一点代码
- 关于GridBagLayout网络上一篇很好的文章
- 关于GridBagLayout网络上一篇很好的文章
- 关于 "Canot access the ClassView information file" 的真正原因及解决办法。
- 分享一篇很好的关于phpExcelReader实现Excel解析的文章~~~~~
- 关于perl的open (MYFILE, "file1") || die ("Could not open file")语句执行原理,路过的高手来指点一二
- 关于tcp/ip &编译原理
- 转一篇关于反射的文章,写的很好
- 关于文件&文件夹加密&隐藏原理的一点想法
- 好文章一篇 转载----关于 ViewState