網站首頁 編程語言 正文
引言
相信有很多小伙伴跟我一樣,一直從事Android上層應用開發,對Android底層充滿興趣,奈何基礎知識薄弱,每次學習源碼進入native層的時候,都想放棄。不用灰心,一遍看不懂就再來一遍,今天主要是分享Android智能指針的內容。
作為上層應用開發者對C++不是很熟悉,不要慌,咱們一步一步來,接下來我將分為3篇文章來講解智能指針
1、智能指針初探——輕量級指針(Light Pointer)
2、智能指針初探——強指針(Strong Pointer)(未更新)
3、智能指針初探——弱指針(Weak Pointer)(未更新)
本篇是智能指針初探——輕量級指針(Light Pointer),在講解智能指針之前我們先思考下為什么java沒有指針。
java
做Android上層應用開發肯定離不開java,很多人選擇學習java最主要的原因是沒有指針,再也不用擔心各種指針和內存釋放了。
//java
Object a = new Object();
java在設計中盡量淡化了指針的概念,我們可以簡單的new對象,上面示例代碼就是java生成一個對象的最簡單樣例,我們可以通過變量a去使用剛剛new好的Object對象。變量a是一個對象類型或者說是引用類型,作用其實跟C/C++中的指針類似。
java中引用分為如下4類,感興趣的同學可以自行去學習:
引用類型 | 概述 |
---|---|
StrongReference(強引用) | 強引用是最經常使用的一種引用,如new操作創建的對象就屬于強引用,只要強引用關系還存在,垃圾收集器就不會回收掉被引用的對象。 |
SoftReferenc(軟引用) | 內存空間足夠,垃圾回收器就不會回收它,如果內存空間不足了,就會回收這些對象的內存,只要垃圾回收器沒有回收它,該對象就可以被程序使用。 |
WeakReferenc(弱引用) | 弱引用也是用來描述那些非必須對象,但是它的強度比軟引用更弱一些,被弱引用關聯的對象只能生存到下一次垃圾收集發生為止。當垃圾收集器開始工作,無論當前內存是否足夠,都會回收掉只 被弱引用關聯的對象 |
PhantomReference(虛引用) | 虛引用也稱為“幽靈引用”或者“幻影引用”,它是最弱的一種引用關系。一個對象是否有虛引用的 存在,完全不會對其生存時間構成影響,也無法通過虛引用來取得一個對象實例。為一個對象設置虛 引用關聯的唯一目的只是為了能在這個對象被收集器回收時收到一個系統通知。 |
這些引用類型配合Java垃圾回收機制(GC),讓我們java程序員不用太關心內存的釋放。Java垃圾回收機制正是由java虛擬機(JVM)提供,在Android也有對應的虛擬機:Dalvik 虛擬機(Dalvik Virtual Machine),ART(Android Runtime)虛擬機。 java在進行垃圾回收機制(GC)時,需要做兩件事:
1、判斷該對象是否為垃圾
2、垃圾回收的具體算法
判斷該對象是否為垃圾
1、引用計數法
原理其實很簡單,給運行的對象添加一個引用計數器,每當有一個地方引用它時,計數器+1;當引用失效時,計數器就-1,任何時刻計數器為0的對象,就視作不可能再被使用。這一種方式,實現簡單,邏輯也清晰,大部分的情況下,它都可以達到很好的效果,盡管這樣,計數器算法還是存在但是的,但是它無法解決循環引用的場景(A、B兩個對象相互引用)。
2、可達性分析法
通過一系列稱為“GC Roots”的對象作為起始點,從這些節點開始向下搜索,搜索走過的路徑稱為“引用鏈”,當一個對象到 GC Roots 沒有任何的引用鏈相連時(從 GC Roots 到這個對象不可達)時,證明此對象不可用。
GC Roots包含以下:
- 虛擬機棧(棧幀中的本地變量表)中引用的對象
- 方法區中類靜態屬性引用的對象
- 方法區中常量引用的對象
- 本地方法棧中JNI(即一般說的native方法)中引用的對象
......
雖然這些虛擬機已幫忙我們回收內存,但其實我們做上層應用開發時還是得特別需要注意引用,不然還是會造成OOM等異常。
垃圾回收的具體算法
java垃圾回收的算法有很多這里就不詳細展開了(標記-清除算法、 標記-整理算法、 復制算法、分代收集算法...),感興趣的同學可以自行學習
C++
相比較java的引用+垃圾回收機制,C++沒有垃圾回收的機制,通常使用引用計數的方法來統計對象的使用情況,為了實現引用計數,需要有個類來負責計數,我們先看下最簡單的輕量級指針(Light Pointer)。
本文中的源代碼可下面鏈接查看:
www.aospxref.com/android-7.1…
www.aospxref.com/android-7.1…
www.aospxref.com/android-7.1…
輕量級指針(Light Pointer)
我們希望指針指向的對象有引用計數功能,當計數為0時,刪除對象,所以需要有個類能夠實現引用計數的功能。
輕量級指針(Light Pointer)的引用計數類就是它:LightRefBase(system/core/include/utils/RefBase.h)
template <class T>
class LightRefBase
{
public:
inline LightRefBase() : mCount(0) { }
inline void incStrong(const void* id) const {
android_atomic_inc(&mCount);
}
inline void decStrong(const void* id) const {
if (android_atomic_dec(&mCount) == 1) {
delete static_cast<const T*>(this);
}
}
//! DEBUGGING ONLY: Get current strong ref count.
inline int32_t getStrongCount() const {
return mCount;
}
protected:
inline ~LightRefBase() { }
private:
mutable volatile int32_t mCount;
};
我們簡單看下這個類,重點關注mCount這個變量的使用,在incStrong中+1,在decStrong是-1(當前mCount為1時,再減就要為0了,就會delete對象)。
好了,現在我們有了引用計數類之后,還缺少一個關鍵角色:指針sp(system/core/include/utils/StrongPointer.h)
template<typename T>
class sp {
public:
inline sp() : m_ptr(0) { }
sp(T* other);
sp(const sp<T>& other);
sp(sp<T>&& other);
template<typename U> sp(U* other);
template<typename U> sp(const sp<U>& other);
template<typename U> sp(sp<U>&& other);
~sp();
// Assignment
sp& operator = (T* other);
sp& operator = (const sp<T>& other);
sp& operator = (sp<T>&& other);
template<typename U> sp& operator = (const sp<U>& other);
template<typename U> sp& operator = (sp<U>&& other);
template<typename U> sp& operator = (U* other);
//! Special optimization for use by ProcessState (and nobody else).
void force_set(T* other);
// Reset
void clear();
// Accessors
inline T& operator* () const { return *m_ptr; }
inline T* operator-> () const { return m_ptr; }
inline T* get() const { return m_ptr; }
// Operators
COMPARE(==)
COMPARE(!=)
COMPARE(>)
COMPARE(<)
COMPARE(<=)
COMPARE(>=)
private:
template<typename Y> friend class sp;
template<typename Y> friend class wp;
void set_pointer(T* ptr);
T* m_ptr;
};
sp類是個模版類,主要的工作就是指針指向m_ptr,在構造函數、析構函數、重載函數(operator =)中控制m_ptr中的計數,而m_ptr指向的對象就是繼承自LightRefBase。
//以下只截取了部分代碼,詳細代碼內容參考 StrongPointer.h
//普通構造函數
template<typename T>
sp<T>::sp(T* other)
: m_ptr(other) {
if (other)
other->incStrong(this);
}
//拷貝構造函數
template<typename T>
sp<T>::sp(const sp<T>& other)
: m_ptr(other.m_ptr) {
if (m_ptr)
m_ptr->incStrong(this);
}
//析構函數
template<typename T>
sp<T>::~sp() {
if (m_ptr)
m_ptr->decStrong(this);
}
//重載函數(operator =)
template<typename T>
sp<T>& sp<T>::operator =(const sp<T>& other) {
T* otherPtr(other.m_ptr);
if (otherPtr)
otherPtr->incStrong(this);
if (m_ptr)
m_ptr->decStrong(this);
m_ptr = otherPtr;
return *this;
}
那么我們該如何使用輕量級指針(Light Pointer):
只需繼承自LightRefBase結合sp即可。
class MyLightRefClass : public LightRefBase<MyLightRefClass>
{
public:
MyLightRefClass()
{
}
virtual ~MyLightRefClass()
{
}
};
int main(int argc, char** argv)
{
MyLightRefClass* lightClass = new MyLightRefClass();
sp<MyLightRefClass> lp = lightClass;
}
輕量級指針的分享就結束了,輕量級指針很簡單但是有一個問題沒有解決:A、B相互引用,關于后面的強指針、弱指針還請繼續關注
原文鏈接:https://juejin.cn/post/7174003890889687076
相關推薦
- 2022-06-18 datagridview實現手動添加行數據_C#教程
- 2021-11-28 C/C++中的?Qt?StandardItemModel?數據模型應用解析_C 語言
- 2022-07-19 Linux手工配置靜態ip地址
- 2022-11-09 GO?語言運行環境的基礎知識_Golang
- 2022-10-26 一文解析?Golang?sync.Once?用法及原理_Golang
- 2022-03-15 pycharm安裝opencv出現錯誤:Could not find a version that
- 2022-11-23 Python字典高級用法深入分析講解_python
- 2022-08-28 go?zero微服務實戰處理每秒上萬次的下單請求_Golang
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支