Chrome學習之LazyInstance

來源:互聯網
上載者:User

    LazyInstance顧名思義,就是延遲創造類執行個體。

    那chrome是怎麼做到的呢?

    為了效能,或者資源,程式中無法立即用到的對象,我們無需立即創造,比如一個介面的菜單對象,當你還沒有點擊菜單之前就創造了,那他一定會影響軟體的啟動效能。

再比如資料庫物件,或者線程...等等,進可能延遲,chrome高效的原因之一,在於調用無數個LazyInstance對象。

研究過chrome的同學應該知道,chrome的管理工作的執行緒模式,他的所有線程(除了主線程),都可以消極式載入的。

    作為消極式載入模版類LazyInstance<Type, Traits>它具備哪些特點呢?

1.安全執行緒。

2.LazyInstance不像單一實例模型Singleton,他可以支援一個類型的多個執行個體。

3,為LazyInstance的類型預先分配空間,減少堆空間產生片段。

4.優美的刪除

    使用方法:

 static LazyInstance<MyClass> my_instance(base::LINKER_INITIALIZED);   void SomeMethod() {     my_instance.Get().SomeMethod();  // MyClass::SomeMethod()     MyClass* ptr = my_instance.Pointer();     ptr->DoDoDo();  // MyClass::DoDoDo  }

    從上可知:

LazyInstance<T>::Get()返回的是對象引用
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).如果需要建立則進行調用

Traits::New

    Chrome提供了預設的Trait以供通用。如果特意為某個類進行聲明new方法,則定義Trait類,並對其New裡面定義相關對象申請方法,然後在LazyInstance第二個模板裡傳進去

3).返回指標

Type* Pointer() {    if (!Traits::kAllowedToAccessOnNonjoinableThread)      base::ThreadRestrictions::AssertSingletonAllowed();    if ((base::subtle::Acquire_Load(&state_) != STATE_CREATED) &&        NeedsInstance()) {      instance_ = Traits::New(buf_);      void (*dtor)(void*) = Traits::Delete;      CompleteInstance(this, (dtor == NULL) ? NULL : OnExit);    }    ANNOTATE_HAPPENS_AFTER(&state_);    return instance_;  }

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執行個體即可顯示釋放記憶體,避免泄露,如下:

void LazyInstanceHelper::CompleteInstance(void* instance, void (*dtor)(void*)) {  base::subtle::Release_Store(&state_, STATE_CREATED);  if (dtor)    base::AtExitManager::RegisterCallback(dtor, instance);}

總結:

     通過分析LazyInsance我們可以知道,Chrome是如何最佳化效能的。

      1.儘可能的減少鎖的範圍。

      2.儘可能消極式載入。

      3.儘可能減少記憶體片段。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.