Android强指针sp和弱指针wp区别(六)
Android 区别 指针 wp sp
2023-09-14 09:09:55 时间
Android强指针sp和弱指针wp区别
1.强指针与弱指针概述
Android中定义了两种智能指针类型,一种是强指针sp(strong pointer),一种是弱指针(weak pointer).
其实成为强引用和弱引用更合适一些。强指针与一般意义的智能指针概念相同,通过引用计数来记录有多少
使用者在使用一个对象,如果所有使用者都放弃了对该对象的引用,则该对象将被自动销毁。
在Android的源代码中,经常会看到形如:sp、wp这样的类型定义,这其实是Android中的智能指针。
智能指针是C++中的一个概念,通过基于引用计数的方法,解决对象的自动释放的问题。在C++编程中,
有两个很让人头痛的问题:一是忘记释放动态申请的对象从而造成内存泄露;二是对象在一个地方释放后,
又在别的地方被使用,从而引起内存访问错误。
Android的智能指针相关的源代码在下面两个文件中:
frameworks/base/include/utils/RefBase.h
frameworks/base/libs/utils/RefBase.cpp
2.强指针与弱指针区别
<1>.弱指针也指向一个对象,但是弱指针仅仅记录该对象的地址,不能通过弱指针来访问该对象,也就是说
不能通过弱指针来调用对象的成员函数或访问对象的成员变量。要想访问弱指针所指向的对象,需首先将弱指针
升级为强指针(通过wp类所提供的promote()方法)。弱指针所指向的对象是有可能在其它地方被销毁的,如
果对象已经被销毁,wp的promote()方法将返回空指针,这样就能避免出现地址访问错的情况。弱指针操作的
就是这个对象,只有当强引用计数和弱引用计数都为0时,这个对象才会被销毁
<2>.为什么要引入“弱引用”指针呢?
弱引用指针就是没有“所有权”的指针。有时候我只是想找个指向这块内存的指针,但我不想把这块内存的生
命周期与这个指针关联。这种情况下,弱引用指针就代表“我指向这东西,但这东西什么时候释放不关我事儿……”
3.循环引用及其解法
在程序员对强弱指针的理解不是很深入的情况下,想当然的认为使用了强指针,系统会根据引用计数自动收
回。
循环引用,就是对象A有个强指针,引用对象B;对象B中,也有个强指针,引用对象A;这样A和B就互锁。A
对象释放B对象的引用是在本身被析构回收时,而析构回收的前提是A对象没有被引用,则需要B对象先释放,B
对象释放的前提是A对象释放…如此则A和B都无法释放,这样即产生了内存泄露(内存泄漏指由于疏忽或错误造
成程序未能释放已经不再使用的内存。 内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后
,由于设计错误,导致在释放该段内存之前就失去了对该段内存的控制,从而造成了内存的浪费。)
<1>.一个内存泄漏的栗子:强强引用
namespace android{
class Bigclass : public RefBase
{
public:
Bigclass(char *name){
strcpy(mName, name);
ALOGD("Construct: %s", mName);
}
~Bigclass(){
ALOGD("destruct: %s", mName);
}
void setStrongRefs(sp<Bigclass> b){
spB = b;
}
private:
sp<Bigclass> spB;
char mName[64];
};
}
//该类只有一个sp指针和一个name成员。循环引用示例:
void testStrongCrossRef(){
sp<Bigclass> A = new Bigclass("testStrongClassA");
sp<Bigclass> B = new Bigclass("testStrongClassB");
A->setStrongRefs(B);
B->setStrongRefs(A);
}
int main(){
ALOGD("Start testStrongClasses..");
testStrongCrossRef();
ALOGD("testStrongClasses Should be destructed!!");
return 0;
}
输出的结果,如预期,对象没有被释放,泄露了:
D/TEST ( 1552): Start testStrongClasses..
D/TEST ( 1552): Construct: testStrongClassA
D/TEST ( 1552): Construct: testStrongClassB
D/TEST ( 1552): testStrongClasses Should be destructed!!
<2>.弱弱引用
解决内存泄漏问题:加入弱引用(弱指针):弱指针仅仅记录该对象的地址,不能通过引用计数来控制所引用对象
的生命周期,这样就可以消除上例中的引用环路问题,使得问题解决。增加了弱引用的接口:
namespace android{
class Bigclass : public RefBase
{
public:
Bigclass(char *name){
strcpy(mName, name);
ALOGD("Construct: %s", mName);
}
~Bigclass(){
ALOGD("destruct: %s", mName);
}
void setStrongRefs(sp<Bigclass> b){
spB = b;
}
void setWeakRefs(sp<Bigclass> b){
wpB = b;
}
private
sp<Bigclass> spB;
wp<Bigclass> wpB;
char mName[64];
};
}
//将上例中的强指针换成弱指针
void testWeakCrossRef(){
sp<Bigclass> A = new Bigclass("testWeakClassA");
sp<Bigclass> B = new Bigclass("testWeakClassB");
A->setWeakRefs(B);
B->setWeakRefs(A);
}
int main(){
ALOGD("Start testStrongClasses..");
testStrongCrossRef();
ALOGD("testStrongClasses Should be destructed!!");
return 0;
}
输出结果:
D/TEST ( 2889): Start testWeakClass ..
D/TEST ( 2889): Construct: testWeakClassA
D/TEST ( 2889): Construct: testWeakClassB
D/TEST ( 2889): destruct: testWeakClassB
D/TEST ( 2889): destruct: testWeakClassA
D/TEST ( 2889): testWeakClass Should be destructed!!
在出了testWeakClassA和testWeakClassB在对象A和B出了作用域后,没有强引用了,两个对象都释放了,
这个符合预期。
这里testWeakClassA和testWeakClassB之间的引用关系,全部都是弱引用,因此二者间的生命周期互不相
干,这里二者用sp对象A和B与创建一般的栈对象 Bigclass A, Bigclass B 的生命周期一样。
Android中,最常用的肯定不是下面两种:
1.强强引用——互不相让,互相绑死,这是绝对禁止的。
2.弱弱引用——互不相干,各管生死。这个对于想要使用引用计数自动管理对象生命周期来说,没什么用处。
<3>.栗子3:强弱引用
最常用的一般是强弱引用关系。强弱引用需要是有从属关系的,具体那个类是用sp引用,哪个是用wp引用,要
看设计的逻辑了。
测试示例:
void testCrossRef(){
sp<Bigclass> A = new Bigclass("testNormalClassA");
sp<Bigclass> B = new Bigclass("testNormalClassB");
A->setStrongRefs(B);
B->setWeakRefs(A);
}
int main(){
ALOGD("Start testStrongClasses..");
testStrongCrossRef();
ALOGD("testStrongClasses Should be destructed!!");
return 0;
}
输出结果:
D/TEST ( 2889): Start test Normal pointer reference ..
D/TEST ( 2889): Construct: testNormalClassA
D/TEST ( 2889): Construct: testNormalClassB
D/TEST ( 2889): destruct: testNormalClassA
D/TEST ( 2889): destruct: testNormalClassB
D/TEST ( 2889): Test Normal pointer reference Should be destructed!!
这种情况下,消除了循环引用,没有了内存泄露问题。 和上一个弱弱引用的例子比较,这里
testNormalClassB的析构在testWeakClassA之后,testWeakClassB的生命周期是受testWeakClassA
控制的,只有testWeakClassA析构,testWeakClassB才会析构。(上面的弱弱引用的测例,说明在无干预
的情况下,应该是testWeakClassB先析构的)
对于强弱指针的使用,使用弱指针是需要特别注意,弱指针指向的对象,可能已经被销毁了,使用前需要通过
promote()方法探测一下
相关文章
- 代码加密 android,Android 开发怎样做代码加密或混淆「建议收藏」
- android签名命令行,Android系统签名位置及命令
- android declare-styleable 和style,android – declare-styleable和style之间的区别
- android declare-styleable 和style,Android 关于declare-styleable属性的写法….
- android 定时器的例子[通俗易懂]
- android调用相册并显示图片_Android获取相册列表
- Android resource linking failed_android sdk location should not
- java单元测试覆盖率_android单元测试覆盖率
- Multiple dex files define Lcom/ta/utdid2/android/utils/AESUtils
- Android scheme呼起App
- 【Android 安全】DEX 加密 ( ProGuard 混淆 | -keepclassmembers 混淆效果 | -keepclasseswithmembernames 混淆效果 )
- 【Android Gradle】安卓应用构建流程 ( Java 源码编译 和 AIDL 文件编译 )
- 【Android 屏幕适配】异形屏适配 ① ( 异形屏类型:刘海屏、水滴屏、挖孔屏 | 沉浸式布局刘海屏适配 | 华为手机异形屏适配注意点 )
- 【错误记录】Android Studio 编译报错 ( Execution failed for task ‘:app:kaptDebugKotlin‘. A failure occurred w )
- Android开发中遇到的问题(二)——新建android工程的时候eclipse没有生成MainActivity和layout布局详解手机开发
- android判断服务是否是运行状态详解编程语言
- Android带来新鲜体验:Linux手机系统下载(手机linux系统下载)
- 报告称 Windows 比 Debian Linux 和 Android 更安全
- Android打开GPS导航并获取位置信息返回null解决方案
- Android开发技巧之永不关闭的Toast信息框(长时间显示而非系统关闭)
- Android中使用ListView绘制自定义表格技巧分享
- android引导界面的实现方法
- android教程之使用popupwindow创建菜单示例
- android开发教程之获取使用当前api的应用程序名称