欢迎来真孝善网,为您提供真孝善正能量书籍故事!

深入解析Android系统中的指针:掌握强弱指针的奥秘

时间:11-08 神话故事 提交错误

大家好,今天给各位分享深入解析Android系统中的指针:掌握强弱指针的奥秘的一些知识,其中也会对进行解释,文章篇幅可能偏长,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在就马上开始吧!

Android 7.0版本上相关代码及位置为:

system/core/libutils/RefBase.cppsystem/core/include/utils/RefBase.hsystem/core/include/utils/StrongPointer.h

C++ 11

C++ 11 中引入了大量新功能,使某些开发变得更加容易。用于引用计数变量

std:atomic 模板类:templatestructatomic;提供原子操作。最初的版本使用了Android平台封装的API。

主要用到两个API:fetch_add和fetch_sub,分别用于加1和减1。

积分fetch_add(积分, memory_order=memory_order_seq_cst) 易失性;

积分fetch_add(积分, memory_order=memory_order_seq_cst);

积分fetch_sub(积分, memory_order=memory_order_seq_cst) 易失性;

积分fetch_sub(积分, memory_order=memory_order_seq_cst);用于线程同步的API,没有找到具体信息。

Atomic_thread_fence参考C++11 Concurrency Guide 6(原子类型详细解释3 std:atomic(续))

这两个API的最后一个参数的类型为std:memory_order。主要是内存模型参数,可以调整代码的执行顺序,告诉编译器优化方法。比如GCC如果添加了O2参数,就会对代码的执行顺序进行一定的调整,但是在多线程中会带来一定的问题。如果发生错误,内存模型参数可以指定编译器的优化方法并限制多个原子语句的执行顺序。

C++11并发指南7(C++11内存模型1:简介)

/*

std:内存顺序

C++ 原子操作库

定义在头文件中*/

枚举内存顺序{

内存顺序放松,

内存_顺序_消耗,

内存_顺序_获取,

内存_顺序_释放,

内存_顺序_acq_rel,

内存顺序seq_cst

};主要用到两个:

std:memory_order_relaxed:线程内顺序执行,线程之间随机执行。 std:memory_order_seq_cst:多线程保持顺序一致性并像单线程一样执行。参考:

std:内存顺序

据说,世界上完全理解这个内容的人屈指可数。

主要的类

1. RefBase

需要能够自动管理内存的对象必须继承该类。 RefBase内部有一个int类型的引用计数。它实际上是通过weakref_impl类型的mRefs来管理的。

RefBase:RefBase() : mRefs(新的weakref_impl(this))

{

}通过==void incStrong(const void* id) const==函数增加引用计数,

refs-incWeak(id);增加弱引用计数。增加强引用计数if const int32_t c=refs-mStrong.fetch_add(1, std:memory_order_relaxed);

返回值c为初始值INITIAL_STRONG_VALUE,执行onFirstRef。 onFirstRef函数体是空的,可以重载做一些初始化工作。通过==void decStrong(const void* id) const==减少引用计数。

减少强引用计数const int32_t c=refs-mStrong.fetch_sub(1, std:memory_order_release);如果c==1,先做一些清理工作:onLastStrongRef,然后删除如果不是1,则删除refs-decWeak(id);void RefBase:incStrong(const void* id) const

{

weakref_impl* const refs=mRefs;

refs-incWeak(id);

refs-addStrongRef(id);

const int32_t c=refs-mStrong.fetch_add(1, std:memory_order_relaxed);

如果(c!=INITIAL_STRONG_VALUE){

返回;

}

int32_t old=refs-mStrong.fetch_sub(INITIAL_STRONG_VALUE,

std:memory_order_relaxed);

refs-mBase-onFirstRef();

}

void RefBase:decStrong(const void* id) const

{

weakref_impl* const refs=mRefs;

refs-removeStrongRef(id);

const int32_t c=refs-mStrong.fetch_sub(1, std:memory_order_release);

如果(c==1){

std:atomic_thread_fence(std:memory_order_acquire);

refs-mBase-onLastStrongRef(id);

int32_t flags=refs-mFlags.load(std:memory_order_relaxed);

if ((flagsOBJECT_LIFETIME_MASK)==OBJECT_LIFETIME_STRONG) {

删除这个;

//由于mStrong 已经递增,所以析构函数没有

//删除引用。

}

}

refs-decWeak(id);

}

2. RefBase::weakref_type

RefBase:weakref_type 主要定义了两个函数:incWeak、decWeak,操作弱引用计数。

void RefBase:weakref_type:incWeak(const void* id)

{

weakref_impl* const impl=static_cast(this);

impl-addWeakRef(id);

const int32_t c __unused=impl-mWeak.fetch_add(1,std:memory_order_relaxed);

ALOG_ASSERT(c=0, "incWeak 在最后一个弱引用后在%p 上调用", this);

}

void RefBase:weakref_type:decWeak(const void* id)

{

weakref_impl* const impl=static_cast(this);

impl-removeWeakRef(id);

const int32_t c=impl-mWeak.fetch_sub(1, std:memory_order_release);

ALOG_ASSERT(c=1, "decWeak 在%p 上调用了太多次", this);

if (c !=1) 返回;

atomic_thread_fence(std:memory_order_acquire);

int32_t flags=impl-mFlags.load(std:memory_order_relaxed);

if ((flagsOBJECT_LIFETIME_MASK)==OBJECT_LIFETIME_STRONG) {

//这是常规的生命周期情况。物体被破坏

//当最后一个强引用消失时。由于weakref_impl

//比对象寿命长,它不会在dtor 中被销毁,并且

//我们必须在这里做。

if (impl-mStrong.load(std:memory_order_relaxed)

==INITIAL_STRONG_VALUE) {

//特殊情况:我们从来没有强引用,所以我们需要

//现在销毁对象。

删除impl-mBase;

} 别的{

//ALOGV("释放旧RefBase %pn 的引用%pn", this, impl-mBase);

删除实现;

}

} 别的{

//这是OBJECT_LIFETIME_WEAK 情况。最后一个弱引用

//消失了,我们可以销毁该对象。

impl-mBase-onLastWeakRef(id);

删除impl-mBase;

}

}==需要注意的是,执行delete时使用了变量mFlags。您可以在下面看到该变量的定义。==

3. RefBase::weakref_impl

RefBase:weakref_impl 继承自RefBase:weakref_type。真正的引用计数是由RefBase的内部类RefBase:weakref_impl管理的。内部有四个变量:mStong、mWeak、mBase、mFlags。 mStrong和sp组合起来负责强引用计数; mWeak 与wp 配合,负责弱引用计数。

类RefBase:weakref_impl : 公共RefBase:weakref_type

{

公共:

std:atomicm强;

std:atomicm弱;

RefBase* const mBase;

std:atomicmFlags;

}

//mFlags 定义

//OBJECT_LIFETIME_STRONG为默认值,对象通过强引用计数来管理生命周期

//OBJECT_LIFETIME_WEAK 对象通过弱引用计数来管理生命周期

枚举{

OBJECT_LIFETIME_STRONG=0x0000,

OBJECT_LIFETIME_WEAK=0x0001,

OBJECT_LIFETIME_MASK=0x0001

};

4. sp 为强指针

负责强引用计数管理。内部有一个m_ptr指针来保存RefBase对象。 “=”运算符重载,调用m_ptr的==incStrong==操作引用计数+1。销毁时调用==decStrong==-1。

templatesp sp:operator=(const sp other) {

T* otherPtr(other.m_ptr);

if(otherPtr)

otherPtr-incStrong(this);

如果(m_ptr)

m_ptr-decStrong(this);

m_ptr=otherPtr;

返回*这个;

}

模板sp:~sp() {

如果(m_ptr)

m_ptr-decStrong(this);

}

5. wp 是弱指针

负责对象之间的解除引用。如果子类保存父类指针,父类保存子类指针,则销毁时子类先被销毁,但父类保留了子类的引用,导致引用计数不为0,子类无法被销毁已删除;那么父类销毁后,子类保留父类的引用计数,父类无法被删除。这时候就需要使用wp来避免这种情况。与sp 一样,wp 重载运算符“=”以在销毁期间调用incWeak 和decWeak。

RefBase中有两个变量mStrong和mWeak,分别存储强引用计数和弱引用计数。只要强引用计数为0,就强制删除。

例如:

我们定义了两个类A和B,销毁后,B用一个wp类型的指针来保存A,销毁时,如果弱引用类型不为0,只要强引用类型为0,就强制删除。 A先被析构,强引用类型为0,软引用类型为1,强制delete,这样B的强引用类型也变成1。当B被析构时,执行del后,强引用类型为0、删除

templatewp wp:operator=(const wp other)

{

weakref_type* otherRefs(other.m_refs);

T* otherPtr(other.m_ptr);

if (otherPtr) otherRefs-incWeak(this);

if (m_ptr) m_refs-decWeak(this);

m_ptr=otherPtr;

m_refs=otherRefs;

返回*这个;

}

模板wp:~wp()

{

if (m_ptr) m_refs-decWeak(this);

}

6. 强弱指针的对比

从类图中可以发现,强指针实现了“.”的重载。 "-"操作符,所以sp可以直接访问类成员,但是wp不能,但是wp可以转换成sptemplatespwp:promote() const

{

产生;

if (m_ptr m_refs-attemptIncStrong(结果)) {

结果.set_pointer(m_ptr);

}

返回结果;

}具体类图如下:

Android指针类图

二 移植到PC

为了编译研究和测试代码,将这三个文件移植到PC环境中。 Andrioid7.0代码针对C++ 11进行了修改,在API的跨平台编译方面做得非常好。没有重大变化。我注释掉了部分Android Log代码,编译通过了。这里也对C++ 11 表示赞赏。平台为MAC,IDE为CLion 2016.3,编译使用CMake。

代码

三 LightRefBase

在不考虑类的相互引用的情况下,引用计数比较简单。 Android提供了LightRefBase模板类

在内部,可变的std:atomicmCount;用于保存引用计数。

模板类LightRefBase

{

公共:

内联LightRefBase() : mCount(0) { }

内联void incStrong(__attribute__((未使用)) const void* id) const {

mCount.fetch_add(1, std:memory_order_relaxed);

}

内联void decStrong(__attribute__((未使用)) const void* id) const {

if (mCount.fetch_sub(1, std:memory_order_release)==1) {

std:atomic_thread_fence(std:memory_order_acquire);

删除static_cast(this);

}

}

//!仅调试: 获取当前强引用计数。

内联int32_t getStrongCount() const {

返回mCount.load(std:memory_order_relaxed);

}

typedef LightRefBase 基类型;

受保护:

内联~LightRefBase() { }

私人:

友元类ReferenceMover;

内联静态void renameRefs(size_t n, const ReferenceRenamer renamer) { }

内联静态void renameRefId(T* ref,

const void* old_id, const void* new_id) { }

私人:

可变的std:atomicmCount;

};初始测试代码如下:

类LightRefBaseTest: 公共LightRefBase{

公共:

LightRefBaseTest(){std:cout "你好,LightRefBaseTest!" std:endl;};

LightRefBaseTest(){std:cout "你好,LightRefBaseTest()!" std:endl;};

};

int main() {

std:cout "你好,世界!" std:endl;

LightRefBaseTest 光测试;

返回0;

}

/*

结果:

你好世界!

你好,LightRefBaseTest!

你好,~LightRefBaseTest()!

进程已完成,退出代码为0

*/修改LightRefBaseTest lightTest为:

int main() {

std:cout "你好,世界!" std:endl;

LightRefBaseTest* lightTest=new LightRefBaseTest();

返回0;

}

/*

结果LightRefBaseTest 没有被破坏:

你好世界!

你好,LightRefBaseTest!

进程已完成,退出代码为0

*/再次修改,使用sp指针,LightRefBaseTest再次被析构:

int main() {

std:cout "你好,世界!" std:endl;

spsp1=new LightRefBaseTest();

返回0;

}

/*

看结果,LightRefBaseTest被破坏了:

你好世界!

你好,LightRefBaseTest!

你好,~LightRefBaseTest()!

进程已完成,退出代码为0

*/查看相互引用:

类LightRefBaseTest2;

类LightRefBaseTest: 公共LightRefBase{

公共:

LightRefBaseTest(){std:cout "你好,LightRefBaseTest!" std:endl;};

LightRefBaseTest(){std:cout "你好,LightRefBaseTest()!" std:endl;};

void setPointer(sppointer){mPointer=指针;};

私人:

spm指针;

};

类LightRefBaseTest2: 公共LightRefBase{

公共:

LightRefBaseTest2(){std:cout "你好,LightRefBaseTest2!" std:endl;};

LightRefBaseTest2(){std:cout "你好,LightRefBaseTest2()!" std:endl;};

void setPointer(sppointer){mPointer=指针;};

私人:

spm指针;

};

int main() {

std:cout "你好,世界!" std:endl;

//LightRefBaseTest* lightTest=new LightRefBaseTest();

spsp1=new LightRefBaseTest();

spsp2=新LightRefBaseTest2();

sp1-setPointer(sp2);

sp2-setPointer(sp1);

返回0;

}

/* 两个类都没有被破坏。当LightRefBaseTest 被析构时,由于LightRefBaseTest2 保存了其引用,因此无法调用delete。同样,LightRefBaseTest2 也不能被破坏。

你好世界!

你好,LightRefBaseTest!

你好,LightRefBaseTest2!

进程已完成,退出代码为0

*/LightRefBase完美的解决了C++新建对象的管理问题,但是它有一个致命的缺陷就是无法解决类之间的相互引用。

wp sp RefBase 配合使用。

image

第一种析构: 析构路线图如图中 A线 所以

类SubRefBaseTest;

类RefBaseTest: 公共RefBase{

公共:

RefBaseTest(){std:cout "你好,RefBaseTest!" std:endl;};

RefBaseTest(){std:cout "你好,RefBaseTest()!" std:endl;};

无效setPointer(sppointer){

mPointer=指针;

};

私人:

spm指针;

};

类SubRefBaseTest: 公共RefBase{

公共:

SubRefBaseTest(){ std:cout "你好,SubRefBaseTest!" std:endl;};

SubRefBaseTest(){std:cout "你好,SubRefBaseTest()!" std:endl;};

无效setPointer(sppointer){

mPointer=指针;

};

私人:

spm指针;

};

int main() {

std:cout "你好,世界!" std:endl;

sprefBaseTest=new RefBaseTest();

spsubRefBaseTest=new SubRefBaseTest();

返回0;

}

/*

你好世界!

你好,参考基准测试!

你好,SubRefBaseTest!

你好,~SubRefBaseTest()!

你好,~RefBaseTest()!

进程已完成,退出代码为0

*/int main() {

std:cout "你好,世界!" std:endl;

sprefBaseTest=new RefBaseTest();

spsubRefBaseTest=new SubRefBaseTest();

refBaseTest-setPointer(subRefBaseTest);

subRefBaseTest-setPointer(refBaseTest);

返回0;

}

/* 仍然无法被破坏

你好世界!

你好,参考基准测试!

你好,SubRefBaseTest!

进程已完成,退出代码为0

*/类RefBaseTest:公共RefBase{

公共:

RefBaseTest(){std:cout "你好,RefBaseTest!" std:endl;};

RefBaseTest(){std:cout "你好,RefBaseTest()!" std:endl;};

无效setPointer(wppointer){

mPointer=指针;

};

私人:

wpm指针;

};

/*

将RefBaseTest引用类型修改为wp即可正常销毁。

这里使用了隐式类型转换,refBaseTest-setPointer(subRefBaseTest);

将强指针转换为弱指针。看一下重载的“=”运算符,为弱引用加一。

你好世界!

你好,参考基准测试!

你好,SubRefBaseTest!

你好,~SubRefBaseTest()!

你好,~RefBaseTest()!

进程已完成,退出代码为0

*/

templatewp wp:operator=(const sp other)

{

weakref_type* newRefs=

其他!=NULL?其他-createWeak(this) : 0;

T* otherPtr(other.m_ptr);

if (m_ptr) m_refs-decWeak(this);

m_ptr=otherPtr;

m_refs=newRefs;

返回*这个;

}

第二种析构

如图中B行所示

int main() {

std:cout "你好,世界!" std:endl;

wpwp1=新的RefBaseTest();

好了,文章到此结束,希望可以帮助到大家。

用户评论

焚心劫

这篇文章是不是讲讲 Android 开发中如何管理内存?

    有19位网友表示赞同!

不识爱人心

我一直对 Java 里的强弱指针不太理解,希望这篇文章能解释得清楚些。

    有10位网友表示赞同!

琴断朱弦

看题目感觉很专业啊,我还要认真学习一下才行。

    有8位网友表示赞同!

各自安好ぃ

Android 开发确实要注重内存管理,分析强弱指针应该很有意义。

    有7位网友表示赞同!

陌潇潇

学习这个知识点可以提高编程效率吧?

    有6位网友表示赞同!

素婉纤尘

不知道Android 强弱指针和Java里的有什么区别

    有7位网友表示赞同!

微信名字

最近想换个手机系统,感觉 Android 真是越来越完善了。

    有5位网友表示赞同!

凉凉凉”凉但是人心

如果能结合实际代码案例分析就更好了!

    有9位网友表示赞同!

蝶恋花╮

好期待看到这篇文章的深度解析,期待学习!

    有5位网友表示赞同!

烟雨萌萌

这篇标题让我想到之前学过一些面向对象编程的概念

    有13位网友表示赞同!

余温散尽ぺ

强弱指针是什么?感觉这个概念在 Android 开发中很重要啊。

    有20位网友表示赞同!

仰望幸福

Android 的开发越来越复杂了,需要不断地学习新知识点才能跟上节奏

    有10位网友表示赞同!

何必锁我心

这篇文章是否适用于所有版本的 Android?

    有17位网友表示赞同!

病态的妖孽

这种类型的文章能不能分享一下学习经验或者常用的技巧呢?

    有6位网友表示赞同!

念安я

看完 这篇文章,我能否写出更优秀的Android应用了呢?

    有19位网友表示赞同!

岁岁年年

希望这篇文章能深入浅出地讲解,让非专业的我也能理解。

    有10位网友表示赞同!

如你所愿

期待作者能够用通俗易懂的语言来讲述这个技术概念!

    有9位网友表示赞同!

别悲哀

学习 Android 开发需要哪些基本知识储备呢?

    有20位网友表示赞同!

仅有的余温

Android 的官方文档是否也有相关的介绍呢?

    有12位网友表示赞同!

安好如初

强弱指针分析在实际开发中可以解决哪些问题呢?

    有14位网友表示赞同!

【深入解析Android系统中的指针:掌握强弱指针的奥秘】相关文章:

1.蛤蟆讨媳妇【哈尼族民间故事】

2.米颠拜石

3.王羲之临池学书

4.清代敢于创新的“浓墨宰相”——刘墉

5.“巧取豪夺”的由来--米芾逸事

6.荒唐洁癖 惜砚如身(米芾逸事)

7.拜石为兄--米芾逸事

8.郑板桥轶事十则

9.王献之被公主抢亲后的悲惨人生

10.史上真实张三丰:在棺材中竟神奇复活