Chrome学习之LazyInstance

 LazyInstance顾名思义,就是延迟创造类实例。

    那chrome是怎么做到的呢?

    为了性能,或者资源,程序中无法立即用到的对象,我们无需立即创造,比如一个界面的菜单对象,当你还没有点击菜单之前就创造了,那他一定会影响软件的启动性能。

再比如数据库对象,或者线程...等等,进可能延迟,chrome高效的原因之一,在于调用无数个LazyInstance对象。

研究过chrome的同学应该知道,chrome的管理任务的线程模型,他的所有线程(除了主线程),都可以延迟加载的。

    作为延迟加载模版类LazyInstance<Type, Traits>它具备哪些特点呢?

1.线程安全。

2.LazyInstance不像单实例模型Singleton,他可以支持一个类型的多个实例。

3,为LazyInstance的类型预先分配空间,减少堆空间产生碎片。

4.优美的删除

    使用方法:

  1. static LazyInstance<MyClass> my_instance(base::LINKER_INITIALIZED);  
  2.   void SomeMethod() {  
  3.     my_instance.Get().SomeMethod();  // MyClass::SomeMethod()   
  4.   
  5.     MyClass* ptr = my_instance.Pointer();  
  6.     ptr->DoDoDo();  // MyClass::DoDoDo   
  7.  }  

    从上可知:

  1. LazyInstance<T>::Get()返回的是对象引用  
  1. LazyInstance<T>::Pointer()返回的是对象指针  

    接下来我们一一说明一下上面所述的特点是怎么做到的。


1.线程安全

    为了线程安全LazyInstance声明了三个标记:

enum {
    STATE_EMPTY    = 0, //没有创建实例
    STATE_CREATING = 1,//正在创建实例,这时另一个被创建的例程应该先被Hold住,第一个先创建完后返回
    STATE_CREATED  = 2//已经创建了,不需要重复创造。
  };


    延迟加载当然是第一次调用Pointer()方法时创建(对于Get()方法,当然里面会调用Pointer方法来实现,尽可能重用代码).

1).Pointer方法首先不用加锁,快速获取state_变量是否已经变成STATE_CREATED状态,如果已经创建了,就直接返回,否则通过加多线程锁进行check一下(调用NeedInstance方法),是否是正在创建状态,如果正在被另一个线程创建,则等待他创建完然后直接返回指针。

这里LazyInstance尽可能地避免了加锁,只要创建完了一个实例后,后续的所有对状态的判断都不会涉及加锁。

2).如果需要创建则进行调用

  1. Traits::New  

    Chrome提供了默认的Trait以供通用。如果特意为某个类进行声明new方法,则定义Trait类,并对其New里面定义相关对象申请方法,然后在LazyInstance第二个模板里传进去

3).返回指针


  1. Type* Pointer() {  
  2.     if (!Traits::kAllowedToAccessOnNonjoinableThread)  
  3.       base::ThreadRestrictions::AssertSingletonAllowed();  
  4.     if ((base::subtle::Acquire_Load(&state_) != STATE_CREATED) &&  
  5.         NeedsInstance()) {  
  6.       instance_ = Traits::New(buf_);  
  7.       void (*dtor)(void*) = Traits::Delete;  
  8.       CompleteInstance(this, (dtor == NULL) ? NULL : OnExit);  
  9.     }  
  10.     ANNOTATE_HAPPENS_AFTER(&state_);  
  11.     return instance_;  
  12.   }  


2.LazyInstance不像单实例模型Singleton,他可以支持一个类型的多个实例。

    通过上面实力可以看出,对每个延迟加载对象进行全局定义即可。


3,为LazyInstance的类型预先分配空间,减少堆空间产生碎片。

     含有成员变量预先为特定类进行分配空间,如下:

int8 buf_[sizeof(Type)];

    这样调用LazyInstance的时候我们用的都是静态全局变量,这些都会存放在静态数据区域,而不是堆区域。对于堆、栈,静态区的一些介绍,参考:http://www.cnblogs.com/avril/archive/2011/04/28/2031886.html

    然后通过调用Trait里New方法,POD( what is POD:http://en.wikipedia.org/wiki/Plain_old_data_structure )类型初始化

    如下:

template <typename Type>
struct DefaultLazyInstanceTraits {
...
  static Type* New(void* instance) {
    return new (instance) Type();
  }

...

}

4.优美的删除

    删除当然也是调用Trait的Delete方法,当然你也可以指定自己定义的Delete方法。

    那Delete是什么时候被调用呢?

    Chrome提供了另一个类AtExitManager来管理全局对象,当整个程序结束时,AtExitManager会调用析构函数,此时会调用注册在AtExitManager里的所有回调函数。

    当创建完LazyInstance对象后,在上面的CompleteInstance方法里注册Delete到AtExitManager实例即可显示释放内存,避免泄露,如下:

  1. void LazyInstanceHelper::CompleteInstance(void* instance, void (*dtor)(void*)) {  
  2.   base::subtle::Release_Store(&state_, STATE_CREATED);  
  3.   if (dtor)  
  4.     base::AtExitManager::RegisterCallback(dtor, instance);  
  5. }  


总结:

     通过分析LazyInsance我们可以知道,Chrome是如何优化性能的。

      1.尽可能的减少锁的范围。

      2.尽可能延迟加载。

      3.尽可能减少内存碎片。

©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值