OpenHarmony使用智能指针管理动态分配内存对象

news2024/9/23 20:07:24

概述

智能指针是行为类似指针的类,在模拟指针功能的同时提供增强特性,如针对具有动态分配内存对象的自动内存管理等。

  • 自动内存管理主要是指对超出生命周期的对象正确并自动地释放其内存空间,以避免出现内存泄漏等相关内存问题。
  • 智能指针对每一个RefBase对象具有两种不同的引用形式。强引用持有对一个对象的直接引用。 具有强引用关系的对象在该强引用关系存在时同样也应当存在,也即该引用关系有效;弱引用持有对一个对象的间接引用。 具有弱引用关系的对象在该弱引用关系存在时并不保证存在。

注意:上述描述仅当正确使用智能指针时才成立。

实现原理

  • 智能指针通过引用计数来实现所指向对象内存的自动管理。每一个可以被智能指针管理的对象都持有一个引用计数器,引用计数器在相关引用计数清0时会调用一个用于销毁该对象的回调函数。

  • 引用计数器记录了对应RefBase对象的两种不同引用计数值,以及对于其本身,即RefCounter对象的引用计数值。

涉及功能

OHOS::sptr

模块: SmartPointer

指向RefBase(或其子类)对象的强引用智能指针。

具体描述
template <typename T >
class OHOS::sptr;

指向RefBase(或其子类)对象的强引用智能指针。

模板参数:

  • T 被sptr管理的具体类型。该类必须继承自RefBase基类。

其直接引用RefBase对象。

#include <refbase.h>

接口说明

OHOS::wptr

模块: SmartPointer

指向RefBase(或其子类)对象的弱引用智能指针。

具体描述
template <typename T >
class OHOS::wptr;

指向RefBase(或其子类)对象的弱引用智能指针。

模板参数:

  • T 被wptr管理的具体类型。该类必须继承自RefBase基类。

其间接引用RefBase对象;直接引用WeakRefCounter对象。

#include <refbase.h>

接口说明

使用示例

  1. 使用方法(伪代码)
#include "../include/refbase.h"
#include <iostream>

using namespace std;
using namespace OHOS;

// 管理目标类
class RefBaseTest : public RefBase {
public:
    virtual void Access()
    {
        cout<<"Access RefBaseTest::Show"<<endl;
    }

    ~RefBaseTest() override
    {
        cout << "RefBaseTest destroyed" << endl;
    }
};

// 管理目标类的子类
class SubRefBaseTest : public RefBaseTest {
public:
    void Access() override
    {
        cout<<"Access SubRefBaseTest::Show"<<endl;
    }

    ~SubRefBaseTest() override
    {
        cout << "SubRefBaseTest destroyed" << endl;
    }
};

int main()
{
    // 1. 使用新创建智能指针,管理新创建对象
    sptr<RefBaseTest> newSptr(new RefBaseTest());
    wptr<RefBaseTest> newWptr(new RefBaseTest());

    // 2. 使用上述智能指针,管理另一个新创建对象
    // 原管理对象析构
    newSptr = new RefBaseTest();
    newWptr = new RefBaseTest();

    // 3. 使用新创建智能指针,指向其他现存智能指针管理对象
    sptr<RefBaseTest> curSptr(newSptr);
    wptr<RefBaseTest> curWptr(newWptr);

    if (curSptr->GetSptrRefCount() == 2 && curSptr->GetWptrRefCount() == 2 && // 2: count
       curWptr->GetWptrRefCount() == 1) {
        cout << "curSptr run as expected" << endl;
    }

    // 4. 使用现存智能指针管理其托管类型的子类对象
    sptr<SubRefBaseTest> subSptr(new SubRefBaseTest());
    wptr<SubRefBaseTest> subWptr(new SubRefBaseTest());

    curSptr = subSptr;
    curWptr = subWptr;

    // 5. 通过->运算符访问成员"
    curSptr->Access();
    curWptr->Access();

    // 6. 通过*运算符解引用
    (*curSptr).Access();
    (*curSptr).Access();

    // 7. 两种智能指针可以管理对方所管理的对象
    sptr<RefBaseTest> scurSptr(new RefBaseTest);
    wptr<RefBaseTest> scurWptr(new RefBaseTest);

    wptr<RefBaseTest> snewWptr(scurSptr);

    sptr<RefBaseTest> soldSptr(new RefBaseTest);
    wptr<RefBaseTest> soldWptr(new RefBaseTest);
    soldSptr = scurWptr; // sptr仅可通过拷贝赋值管理wptr所管理对象
    soldWptr = scurSptr; // 原本的引用关系将被释放

    if (snewWptr->GetWptrRefCount() == 3 && soldSptr->GetSptrRefCount() == 1 && // 3: count
        soldWptr->GetWptrRefCount() == 3) { // 3: count
            cout << "Smart Pointer assignment run as expected" << endl;
        }
    // 8. wptr可升级为sptr
    sptr<RefBaseTest> spromotedWptr = snewWptr.promote(); // 升级失败时返回空sptr对象,即未管理具体对象的sptr对象
    if (spromotedWptr->GetSptrRefCount() == 2 && spromotedWptr->GetWptrRefCount() == 4) { // 2, 4: count
        cout << "Promote run as expected" << endl;
    }

    return 0;
}
  1. 测试用例编译运行方法
  • 测试用例代码参见 base/test/unittest/common/utils_refbase_test.cpp

  • 使用开发者自测试框架,使用方法参见: 开发自测试执行框架-测试用例执行

  • 使用以下具体命令以运行refbase.h对应测试用例

run -t UT -tp utils -ts UtilsRefBaseTest
  1. debug功能 RefTracker作为debug工具被添加入refbase文件中,以便开发者对RefBase相关问题进行定位。该功能需要重新编译动态库替换系统原有动态库来上机使用(如是静态依赖则需开发者独立审视使能方法)。
  • 全局追踪

全局追踪功能通过编译宏控制,可以追踪全局的RefBase及其子类的轨迹,但同时会对整机性能造成影响。 全局追踪中我们提供了立即打印模式及非立即打印模式。立即打印模式会在每次引用计数发生变化时对计数进行打印。非立即打印模式会在RefBase及其子类对象析构时对轨迹进行打印。

全局追踪、立即打印编译命令:

./build.sh --product-name xxx --ccache --build-target commonlibrary/c_utils/base:utils --gn-args c_utils_debug_refbase=true --gn-args c_utils_track_all=true --gn-args c_utils_print_track_at_once=true

全局追踪、非立即打印编译命令:

./build.sh --product-name xxx --ccache --build-target commonlibrary/c_utils/base:utils --gn-args c_utils_debug_refbase=true --gn-args c_utils_track_all=true
  • 独立追踪

独立追踪功能同样能通过编译宏控制。我们为开发者提供了RefBase::EnableTracker()接口来对某个具体实例使能追踪功能。独立追踪对性能影响很小,可以忽略不计。在独立追踪中我们能同样提供了立即打印及非立即打印模式。

独立追踪、立即打印编译命令:

./build.sh --product-name xxx --ccache --build-target commonlibrary/c_utils/base:utils --gn-args c_utils_debug_refbase=true --gn-args c_utils_print_track_at_once=true

独立追踪、非立即打印编译命令:

./build.sh --product-name xxx --ccache --build-target commonlibrary/c_utils/base:utils --gn-args c_utils_debug_refbase=true
  • 使用方法

编译动态库,编译产物路径为./out/xxx/commonlibrary/c_utils/libutils.z.so

编译产物需要推入系统进行替换,64位系统位于/system/lib64/,32位系统位于/system/lib/

追踪结果通过log打印。格式如下:

// 立即打印
(sptr pointer) start tracking
(sptr pointer) call (RefBase pointer). strong: x weak: x refcnnt: x
...
(sptr pointer) call (RefBase pointer). strong: x weak: x refcnnt: x
(sptr pointer) end tracking

// 非立即打印
(sptr pointer) start backtrace
(sptr pointer) call (RefBase pointer). strong: x weak: x refcnnt: x PID: xxx TID: xxx
...
(sptr pointer) call (RefBase pointer). strong: x weak: x refcnnt: x PID: xxx TID: xxx
(sptr pointer) end backtrace

常见问题

  1. 使用本实现智能指针时,同时使用裸指针或std标准库智能指针(std::shared_ptr)

    • 会造成管理冲突,导致非法访问以及未定义行为,如内存重复释放。
      • 因此也不推荐先创建裸指针后,再使用智能指针管理。
RefBase* a = new RefBase();
sptr<RefBase> s = a;
// 或
sptr<RefBase> s(a); // 裸指针a容易被误delete,造成sptr功能失常
  1. 智能指针需构造在栈上,管理的对象需要在堆上(动态分配对象)

    • 智能指针若构造在堆上则不符合定义。
    • 管理对象若构造在栈上,则会自动释放,错误绕开智能指针管控。
  2. 智能指针不保证线程安全,使用者需保证线程安全以避免同时对同一个sptr对象赋值等操作

  3. 避免通过隐式转换构造智能指针对象

    • 易造成误解。
    • 因编译器优化程度具有不确定的行为,易造成问题。
  4. 不建议使用对象指针构造智能指针对象

    • 外部提前以指针形式释放对象后,继续通过智能指针中使用
    • sptr引用计数为0释放对象,对象指针依旧在外被继续使用
Refbase *a = new Refbase(arg1, arg2);
sptr<Refbase> sp1 = a; // 不建议,对象指针a暴露在外,存在风险
sptr<Refbase> sp2(a); // 不建议,对象指针a暴露在外,存在风险
sptr<Refbase> sp3 = sptr<Refbase>::MakeSptr(arg1, arg2); // 建议,在内部构造Refbase对象,直接交与sptr管控使用
  1. wptr使用注意

    • 在未设置ExtendObjectLifetime的情况下,wptr不参与被管理对象的生命周期控制,对象生命周期由sptr的引用计数控制,但在极特殊情况下存在例外
// 由于历史设计原因,可以在sptr不存在的情况下,基于对象指针创建wptr对象。
// 在未设置ExtendObjectLifetime,且无sptr被创建的特殊少见情况下,为了防止内存泄漏,在wptr引用计数归0时会释放管理对象
Refbase *a = new Refbase(arg1, arg2);
wptr<Refbase> wp1(a);
wp1 = nullptr; // 弱引用计数归0,对象释放,应避免再次手动释放

wptr<Refbase> wp2 = new Refbase(arg1, arg2);
wp2 = nullptr; // 弱引用计数归0,对象释放,这种情况无法手动释放, 如果wptr不能控制对象释放则必然会发生内存泄漏

为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

《鸿蒙开发学习手册》:

如何快速入门:https://qr21.cn/FV7h05

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. ……

开发基础知识:https://qr21.cn/FV7h05

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ……

基于ArkTS 开发:https://qr21.cn/FV7h05

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ……

鸿蒙开发面试真题(含参考答案):https://qr18.cn/F781PH

鸿蒙开发面试大盘集篇(共计319页):https://qr18.cn/F781PH

1.项目开发必备面试题
2.性能优化方向
3.架构方向
4.鸿蒙开发系统底层方向
5.鸿蒙音视频开发方向
6.鸿蒙车载开发方向
7.鸿蒙南向开发方向

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1542831.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

装修行业万能DIY小程序源码系统 带完整的安装的代码包以及搭建教程

在如今数字化、智能化的时代背景下&#xff0c;装修行业也迎来了前所未有的发展机遇。为了满足广大装修从业者及业主的需求&#xff0c;罗峰给大分享了这款装修行业万能DIY小程序源码系统。该系统不仅提供了完整的安装代码包&#xff0c;还附带了详细的搭建教程&#xff0c;让用…

零基础入门数据挖掘系列之「特征工程」

摘要&#xff1a;对于数据挖掘项目&#xff0c;本文将学习应该从哪些角度做特征工程&#xff1f;从哪些角度做数据清洗&#xff0c;如何对特征进行增删&#xff0c;如何使用PCA降维技术等。 特征工程&#xff08;Feature Engineering&#xff09;对特征进行进一步分析&#xf…

详解机器学习概念、算法

目录 前言 一、常见的机器学习算法 二、监督学习和非监督学习 三、常见的机器学习概念解释 四、深度学习与机器学习的区别 基于Python 和 TensorFlow 深度学习框架实现简单的多层感知机&#xff08;MLP&#xff09;神经网络的示例代码&#xff1a; 欢迎三连哦&#xff01; 前言…

美团2024届秋招笔试第二场编程真题

要么是以0开头 要么以1开头 选择最小的答案累加 import java.util.Scanner; import java.util.*; // 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和…

批量高效剪辑视频,轻松调整视频时长,轻松打造完美节奏

在数字化时代&#xff0c;视频内容已成为我们生活中不可或缺的一部分。无论是社交媒体上的短视频&#xff0c;还是专业影视制作中的长片&#xff0c;视频剪辑都扮演着至关重要的角色。然而&#xff0c;面对大量视频素材&#xff0c;如何高效地进行剪辑调整&#xff0c;让每一帧…

临床数据采集痛点有哪些?怎样解决临床数据问题?

临床医学离不开数据采集&#xff0c;但想要得到高质量数据还是比较难&#xff0c;因为数据来源比较多&#xff0c;传统数据采集方式给临床医生带来诸多不便。 临床数据采集有哪些&#xff1f; 1、医院HIS、LIS系统 2、病案室档案和文件 3、医院信息科采集的数据 4、平时自…

cocos3.0资源管理

AssetBundle 官方文档&#xff1a;点击这里 资源缓存 官方文档&#xff1a;点击这里 引擎下载资源的逻辑如下&#xff1a;1.判断资源是否在游戏包内&#xff0c;如果在则直接使用&#xff1b;2.如果不在则查询资源是否在本地缓存中&#xff0c;如果在则直接使用&#xff1b;3.…

2024国自然状态 “已审核”代表什么?

2024年3月18日&#xff0c;16:00是今年国自然集中受理期项目的截止申报时间。 目前&#xff0c;已有多位申请人表示&#xff1a;提交的2024年国自然项目的状态&#xff0c;变成了已审核。 “已审核”代表啥&#xff1f; 图源&#xff1a;网络 申请人登录基金委ISIS系统&#…

LeetCode每日一题——移除链表元素

移除链表元素OJ链接&#xff1a;203. 移除链表元素 - 力扣&#xff08;LeetCode&#xff09; 题目&#xff1a; 思路&#xff1a; 这与之前的移除元素的题目很相似&#xff0c;那么我们同样可以用类似的做法&#xff08;双指针&#xff09;进行解题。但是这是一个链表删除&a…

C语言回顾笔记

1.变量 2.运算符 3.if判断 4.接力break 5.最大公约数 6.水仙花数 #include<stdio.h> int main(){int n;scanf("%d",&n);//根据输入的位数计算&#xff0c;如最小三位数100 int first 1;int i 1;while(i<n){first *10;i; }printf("first%d\n"…

文献阅读笔记(Transformer)

文献阅读笔记&#xff08;Transformer&#xff09; 摘要Abstract1、文献阅读1.1 文献题目1.2 文献摘要1.3 研究背景1.4 模型架构1.4.1 Encoder-Decoder1.4.2 注意力机制1.4.3 多头注意力1.4.4 Position-wise Feed-Forward Networks1.4.5 Embeddings and Softmax1.4.6 Positiona…

【Linux】线程互斥{线程间的互斥相关背景概念/锁的相关问题/锁的原理/可重入VS线程安全}

文章目录 0.计算机如何完成y a * b c &#xff1f;1.线程间的互斥相关背景概念2.pthread_mutex_t3.pthread_mutex_lock()4.time() or gettimeofday5.锁的相关问题6.锁的原理7.可重入VS线程安全8.完善后的代码 0.计算机如何完成y a * b c &#xff1f; 来源&#xff1a; 王道…

【漏洞复现】netgear路由器 boarddataww 存在RCE漏洞

免责声明&#xff1a;文章来源互联网收集整理&#xff0c;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该…

【Linux】详细分析/dev/loop的基本知识 | 空间满了的解决方法

目录 前言1. 基本知识2. 内存满了2.1 清空2.2 扩增 3. 彩蛋 前言 服务器一直down机&#xff0c;翻找日志文件一直找不到缘由&#xff0c;最终发现是挂载的内存满了&#xff0c;那本身这个文件就什么用呢&#xff1f; 1. 基本知识 /dev/loop是一种特殊的设备文件&#xff0c;…

Python JIT 编译器库之Pyjion使用详解

概要 Pyjion 是一个针对 Python 解释器的 JIT 编译器,旨在提高 Python 代码的性能。本文将深入探讨 Pyjion 库的特性、用法,并通过丰富的示例代码展示其在实际项目中的应用。 Pyjion 简介 Pyjion 是一个用于 Python 解释器的 JIT(即时编译)编译器,它的目标是通过实时编译…

二叉树试题解析

一、单项选择题 01.下列关于二叉树的说法中&#xff0c;正确的是( C ). A.度为2的有序树就是二叉树 B.含有n个结点的二叉树的高度为 C.在完全二叉树中&#xff0c;若一个结点没有左孩子&#xff0c;则它必是叶结点 D.含有n个结点的完全二叉树的高度为解析&#xff1a;A 二叉树…

Ubuntu Desktop - Updates (不升级到新版本)

Ubuntu Desktop - Updates [不升级到新版本] 1. UpdatesReferences 1. Updates System Settings -> Software & Updates -> Updates ubuntu-16.04.3-desktop-amd64.iso 不升级到新版本 ​ References [1] Yongqiang Cheng, https://yongqiang.blog.csdn.net/

基于nodejs+vue的ITS 信息平台的设计与实现python-flask-django-php

本论文的主要内容包括&#xff1a; 第一&#xff0c;研究分析当下主流的web技术&#xff0c;结合信息日常管理方式&#xff0c;进行信息平台的数据库设计&#xff0c;设计 信息平台功能&#xff0c;并对每个模块进行说明。 第二&#xff0c;陈列说明该系统实现所采用的架构、系…

Nvidia GPU系列产品分析

概述 Nvidia的GPU发展了30多年&#xff0c;已经逐渐形成了消费级、专业级、AI加速等不同计算任务的GPU系列。 纵观Nvidia的GPU发展历程&#xff0c;其不断迭代的GPU架构以及性能强劲的GPU互联技术成了Nvidia始终站在市场顶峰的决胜法宝。 当前Nvidia企业级GPU的互联架构 Nv…

Netty学习——源码篇5 EventLoop

1 Reactor线程模型 Reactor线程模型 中对Reactor的三种线程模型——单线程模型、多线程模型、主从多线程模型做了介绍&#xff0c;这里具体分析Reactor在Netty中的应用。 1.1单线程模型 单线程模型处理流程如下图&#xff1a; 单线程模型&#xff0c;即Accept的处理和Handler…