智能指針是一種資源管理類,通過對原始指針進行封裝,在資源管理對象進行析構時對指針指向的內存進行釋放;通常使用引用計數方式進行管理。
一個基本實現如下:
1 class Counter{ 2 public: 3 friend Class SmartPointer; 4 Counter() { 5 ptr = NULL; 6 cnt = 0; 7 } 8 9 Counter(Object* p) { 10 ptr = p; 11 cnt = 1; 12 } 13 14 ~Counter() { 15 delete ptr; 16 } 17 private: 18 Object* ptr; 19 int cnt; 20 }; 21 22 Class SmartPointer { 23 public: 24 SmartPointer(Object* p) { 25 ptr_counter = new Counter(p); 26 } 27 28 SmartPointer(const SmartPointer& sp) { 29 ptr_counter = sp.ptr_counter; 30 ptr_counter->cnt++; 31 } 32 33 ~SmartPointer() { 34 ptr_counter->cnt--; 35 if (ptr_counter->cnt == 0) { 36 delete ptr_counter; 37 } 38 } 39 40 SmartPointer& operator=(const SmartPointer& sp) { //別忘了const 41 ptr_counter->cnt--; 42 if (ptr_counter->cnt == 0) { 43 delete ptr_counter; 44 } 45 ptr_counter = sp.ptr_counter; 46 ptr_counter->cnt++;
return *this; // 賦值運算符重載都要返回*this 47 } 48 private: 49 Counter* ptr_counter; 50 };
Counter里的指針是Object*,因為是它也是指向這塊內存的。
引用計數類Counter相當於對指針和cnt變量的一個包裝。智能指針里把所有Object*類型的指針都轉換成Counter*類型來處理。
follow up:
一、如何獲取智能指針所包裝的指針和對象?
solution1:(naive)
定義Object* GetPtr(), Object& GetObject(), 直接返回指針和指針的解引用。
solution2:(good)
對指針的 ->(成員訪問)和 *(解引用)進行運算符重載。【運算符重載原理見此文】
即,在成員函數定義里加入這兩個:
1 Object* operator->() { 2 return ptr_counter->ptr; 3 } 4 5 Object& operator*() { 6 return *(ptr_counter->ptr); 7 }
注意:成員訪問符號->的重載是有遞歸性質的。
二、引用計數帶來的問題:循環引用
如何解決循環引用?
把循環引用的一方使用弱引用(weak_ptr),即可解除循環引用。 ref ref2
三、auto_ptr, unique_ptr, shared_ptr的比較
http://blog.csdn.net/worldwindjp/article/details/18843087
目前最基本的垃圾收集算法有四種:
1. 標記-清除算法(mark-sweep),
2. 標記-壓縮算法(mark-compact),
3. 復制算法(copying)
4. 引用計數算法(reference counting)
具體原理:(示意圖可參考ref0)
1.標記-清除算法 ref
缺點:造成大量內存碎片
2.標記-壓縮算法
該算法標記階段和Mark-Sweep一樣,但是在完成標記之后,它不是直接清理可回收對象,而是將存活對象都向一端移動,然后清理掉端邊界以外的內存。
3.復制算法
它將可用內存按容量划分為大小相等的兩塊,每次只使用其中的一塊。當這一塊的內存用完了,就將還存活着的對象復制到另外一塊上面,然后再把已使用的內存空間一次清理掉,這樣一來就不容易出現內存碎片的問題。
缺點:卻對內存空間的使用做出了高昂的代價,因為能夠使用的內存縮減到原來的一半。如果存活對象很多,那么Copying算法的效率將會大大降低。
4.引用計數算法
缺點:循環引用問題
Generational Collection(分代收集)算法
分代收集算法是目前大部分JVM的垃圾收集器采用的算法。它的核心思想是根據對象存活的生命周期將內存划分為若干個不同的區域。一般情況下將堆區划分為老年代(Tenured Generation)和新生代(Young Generation),老年代的特點是每次垃圾收集時只有少量對象需要被回收,而新生代的特點是每次垃圾回收時都有大量的對象需要被回收,那么就可以根據不同代的特點采取最適合的收集算法。
目前大部分垃圾收集器對於新生代都采取Copying算法,因為新生代中每次垃圾回收都要回收大部分對象,也就是說需要復制的操作次數較少;
而由於老年代的特點是每次回收都只回收少量對象,一般使用的是Mark-Compact算法。
