Search…

Design Pattern: Reference Counting

26/09/20203 min read
Bài viết giới thiệu một phương pháp quản lý vùng nhớ dùng chung giữa các con trỏ - Reference Counting.

Ý tưởng

Xuất phát từ thực tế nhiều biến con trỏ (pointer) có thể dùng chung 1 vùng nhớ, khi hủy 1 pointer bằng từ khóa delete trong C++, các pointer khác dùng chung vùng nhớ đó sẽ rơi vào trạng thái "trỏ đến hư vô" (NULL). Nếu giải phóng vùng nhớ đó 1 lần nữa sẽ gây ra lỗi vì 1 vùng nhớ không thể được giải phóng 2 lần. Do đó, hoặc là phải rất cẩn thận khi giải phóng 1 pointer, hoặc 1 phương pháp đơn giản để tự động quản lý công việc này.

Reference Counting sử dụng 1 biến đếm số lượng pointer trỏ vào 1 vùng nhớ. Khi có các pointer cùng trỏ đến 1 vùng nhớ, hoặc 1 pointer không còn trỏ đến vùng nhớ đó nữa, biến này sẽ được cập nhật lại tương ứng. Vùng nhớ sẽ thực sự được giải phóng khi biến đếm có giá trị bằng 0, hay nói cách khác là không còn pointer nào trỏ đến nó.

Vùng nhớ truyền thống
Vùng nhớ trỏ bởi 4 con trỏ
Vùng nhớ được thu hồi
Vùng nhớ không còn được trỏ

Hiện thực Reference Counting

class ReferenceCounting
{
private:
       int    m_counter;
public:
       ReferenceCounting() : m_counter(0){}
       virtual ~ReferenceCounting(){}

       void   Grab(){ m_counter++; }
       void   Release()
       {
              m_counter--;
              if(m_counter == 0)
                     delete (ReferenceCounting*)this;
       }
};

Trong hiện thực của lớp có các thành phần với chức năng như sau:

  • Biến m_counter: số lượng các pointer đang cùng trỏ vào vùng nhớ.
  • Hàm Grab: quản lý việc thêm 1 pointer khác trỏ vào vùng nhớ.
  • Hàm Release: giải phóng vùng nhớ khi không còn pointer nào trỏ đến.

Sử dụng Reference Counting

Ở khai báo lớp, cho lớp kế thừa từ ReferenceCounting để kích hoạt khả năng quản lý vùng nhớ của ReferenceCounting.

Với mỗi trường hợp 1 pointer cần trỏ đến 1 biến cùng kiểu đã được khởi tạo, gọi hàm Grab để tăng giá trị của biến đếm.

Khi 1 pointer hết giá trị sử dụng, gọi hàm Release để kiểm tra và giải phóng vùng nhớ của pointer đó.

 Ví dụ, sử dụng trong Project Sins (STDIO):

#include <stdio.h>

class ReferenceCounting
{
private:
       int           m_counter;
public:
       ReferenceCounting() : m_counter(0){}
       virtual ~ReferenceCounting(){}

       void   Grab(){ m_counter++; }
       void   Release()
       {
              m_counter--;
              if(m_counter == 0)
                     delete (ReferenceCounting*)this;
       }
};

// Singleton
template <class T> class Singleton
{
private:
       static T*     s_instance;
public:
       Singleton(){}
       virtual ~Singleton(){}

       static T*     GetInstance()
       {
              {
                     if(!s_instance)
                           s_instance = new T();
                     return s_instance;
              }
       }
};

template <class T>
T* Singleton<T>::s_instance = NULL;

// Class derive from ReferenceCounting
class StdioFacebookPlugin : public ReferenceCounting, public Singleton<StdioFacebookPlugin>
{
private:
       // Some necessary variables
       int           m_loginState;
       int           m_shareState;
public:
       StdioFacebookPlugin(){}
       virtual ~StdioFacebookPlugin(){}

       // Some neccesary function
       int           StdioShare(){ return 1; }
       int           StdioLogin(){ return 1; }

       void          SetLoginState(int _state){ m_loginState = _state; }
       int           GetLoginState(){ return m_loginState; }
       void          SetShareState(int _state){ m_shareState = _state; }
       int           GetShareState(){ return m_shareState; }
};

StdioFacebookPlugin * FacebookLogin()
{
       // ...

       StdioFacebookPlugin* plugin = Singleton< StdioFacebookPlugin >::GetInstance();
       plugin->Grab();
       plugin->SetLoginState(plugin->StdioLogin());

       // ...
       return plugin;
}

StdioFacebookPlugin * FacebookSharing()
{
       // ...

       StdioFacebookPlugin* plugin = Singleton<StdioFacebookPlugin>::GetInstance();
       plugin->Grab();
       plugin->SetShareState(plugin->StdioShare());

       // ...
       return plugin;
}

int main()
{
       // ...
       StdioFacebookPlugin* login = FacebookLogin();
       StdioFacebookPlugin* share = NULL;

       if(login)
       {
              share = FacebookSharing();
       }
       else
       {
              printf("Can't login.\n");
       }

       // ...

       login->Release();
       if(share)
              share->Release();

       return 0;
}
IO Stream

IO Stream Co., Ltd

30 Trinh Dinh Thao, Hoa Thanh ward, Tan Phu district, Ho Chi Minh city, Vietnam
+84 28 22 00 11 12
developer@iostream.co

383/1 Quang Trung, ward 10, Go Vap district, Ho Chi Minh city
Business license number: 0311563559 issued by the Department of Planning and Investment of Ho Chi Minh City on February 23, 2012

©IO Stream, 2013 - 2024