(delphi11最新学习资料) Object Pascal 学习笔记---第13章第4节 (内存管理和接口)
13.4 内存管理和接口
在第11章中,我介绍了接口的内存管理的关键要素。与对象不同,接口是受管理且具有引用计数。如我所提到的,接口引用会增加所引用对象的引用计数,但您可以声明接口引用为弱引用以禁用引用计数(但仍然要求编译器为你管理引用),或者您可以使用unsafe修饰符完全禁用对特定引用的任何编译器支持。在这一节中,我们将深入探讨这个领域,展示一些在第11章中提供示例之外的额外示例。
13.4.1 关于弱引用的更多内容
Delphi 对接口使用的引用计数模型存在一个问题,即如果两个对象相互引用,它们将形成循环引用,并且它们的引用计数基本上永远不会降至零。弱引用提供了一种打破这些循环的机制,允许您定义一个不会增加引用计数的引用。
假设两个接口使用它们的字段相互引用,而外部变量引用第一个接口。第一个对象的引用计数将为2(外部变量和第二个对象的字段),而第二个对象的引用计数为1(第一个对象的字段)。图13.4描述了这种情况。
图 13.4: 对象间的引用 对象之间的引用可以形成循环、 弱引用的原因
现在,当外部变量退出作用域时,两个对象的引用计数为1;并且,由于拥有Object2的主对象Object1没有外部所有者,因此这两个对象将无限期保留在内存中。为解决这种情况,您应该打破循环引用,这是一件相当复杂的事情,因为您不知道何时执行此操作(应在最后一个外部引用超出范围时执行,但这是对象无法知道的事实)。
解决这种情况以及许多类似情况的方法是使用弱引用。如前所述,弱引用是对对象的引用,不会增加其引用计数。从技术上讲,您通过对其应用[weak]attribute来定义弱引用。
注解: Attributes是第16章将介绍的Object Pascal高级语言功能。简而言之,它们是一种关于符号的添加一些运行时信息的方法,以便外部代码可以确定如何处理它。
再考虑一下先前的场景,如果从第二个对象对第一个对象的引用是弱引用(见图13.5),那么当外部变量超出作用域时,两个对象都将被销毁。

让我们用代码来看看这种简单情况。首先,ArcExperiments 应用程序示例声明了两个接口,一个引用另一个:
typeIMySimpleInterface = interface['{B6AB548A-55A1-4D0F-A2C5-726733C33708}']procedure DoSomething(BRaise: Boolean = False);function RefCount: Integer;end;IMyComplexInterface = interface['{5E8F7B29-3270-44FC-B0FC-A69498DA4C20}']function GetSimple: IMySimpleInterface;function RefCount: Integer;end;
程序的代码定义了两个实现这些接口的不同类。注意交叉引用(FOwnedBy和FSimple基于接口,其中一个被定义为弱引用):
typeTMySimpleClass = class(TInterfacedObject, IMySimpleInterface)private[Weak] FOwnedBy: IMyComplexInterface;publicconstructor Create(Owner: IMyComplexInterface);destructor Destroy; override;procedure DoSomething(BRaise: Boolean = False);function RefCount: Integer;end;TMyComplexClass = class(TInterfacedObject, IMyComplexInterface)privateFSimple: IMySimpleInterface;publicconstructor Create;destructor Destroy; override;function GetSimple: IMySimpleInterface;function RefCount: Integer;end;
这个“complex”类的构造函数创建了另一个类的对象:
constructor TMyComplexClass.Create;
begininherited Create;FSimple := TMySimpleClass.Create(Self);
end;
请记住,FOwnedBy字段是一个弱引用,因此它不会增加其引用对象的引用计数,在本例中,它不会增加 TMyComplexClass 的引用计数。在本例中是当前对象(Self)。鉴于此代码结构,我们可以编写:
class procedure TMyComplexClass.CreateOnly;
varMyComplex: IMyComplexInterface;
beginMyComplex := TMyComplexClass.Create;MyComplex.FSimple.DoSomething;
end;
只要使用弱引用,这将不会导致内存泄漏。例如,使用以下代码:
varMyComplex: IMyComplexInterface;
beginMyComplex := TMyComplexClass.Create;Log('Complex = ' + MyComplex.RefCount.ToString);MyComplex.GetSimple.DoSomething(False);
鉴于每个构造函数和析构函数都记录了其执行,您将得到一个类似于以下的日志:
kotlinCopy codeComplex class created
Simple class created
Complex = 1
Simple class doing something
Complex class destroyed
Simple class destroyed
如果在代码中删除weak属性,你会看到一个内存泄漏,并且(在上面的代码执行中)引用计数为2而不是1。
相关文章:
(delphi11最新学习资料) Object Pascal 学习笔记---第13章第4节 (内存管理和接口)
13.4 内存管理和接口 在第11章中,我介绍了接口的内存管理的关键要素。与对象不同,接口是受管理且具有引用计数。如我所提到的,接口引用会增加所引用对象的引用计数,但您可以声明接口引用为弱引用以禁用引用计数(但…...
【记录贴】docker镜像格式报错
1,错误内容 最近想要补一补docker的基础知识,跟着练习的时候,发现下面的错误。 换了其他镜像(docker pull ubantu)也存在同样的问题: 错误内容:docker: mediaType in manifest should be appli…...
设计模式 19 模板模式 Template Pattern
设计模式 19 模板模式 Template Pattern 1.定义 模板模式(Template Pattern)是一种行为设计模式,它定义了一个算法的骨架,将一些步骤的具体实现延迟到子类中。在模板模式中,定义了一个抽象类,其中包含了一个…...
PHP如何实现实时计算使用者消耗服务器资源费用?
最近几天遇到一个客户,提出一个很有意思的东西!当然客户的项目方案这里不方便说,这里就假定客户的项目是腾讯云?哈哈哈哈哈 以前客户的收费方案是按月、按季度、按年收费,现在半路杀出了很多程咬金,导致之前的收费方案有点儿贵,没啥性价比,那就搞一个看起来很“便宜”…...
在C++中自定义命名空间,在命名空间中定义string变量,同时定义一个函数实现单词逆置
代码 #include <iostream> #include <cstring> using namespace std; namespace my_space {string s;void reverse(string s);//定义逆置函数 } using namespace my_space; void my_space::reverse(string s){int lens.size();int i0;int jlen-1;while(i<j){//…...
【leetcode 141】环形链表——快慢指针(龟兔赛跑)
给你一个链表的头节点 head ,判断链表中是否有环。 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(…...
容器(Container)的详细介绍
容器,作为现代软件开发和部署的核心技术之一,已经成为云计算、微服务架构等领域的基石。容器技术通过提供轻量级的虚拟化环境,实现了应用程序的快速部署、迁移和扩展,极大地提高了软件开发的效率和灵活性。本文将详细介绍容器的概…...
Python 网格变换之平移、旋转、缩放、变换矩阵
网格变换 一、平移1.1、代码示例1.2、结果示例二、旋转2.1、代码示例2.2、结果示例三、缩放3.1、代码示例3.2、结果示例四、变换矩阵4.1、代码示例4.2、结果示例一、平移 网格平移:将网格沿着特定的方向移动一段距离。 1.1、代码示例...
推荐10款优秀的组件库(一)
1.Ant Desgin UI 网址: https://ant-design-mobile.antgroup.com/zh Ant Design - 一套企业级 UI 设计语言和 React 组件库 "Ant Design Mobile"是一个在线的移动端Web体验平台,让你探索移动端Web的体验极限。 添加图片注释,不…...
freertos的信号量和互斥锁学习笔记
freertos的信号量和互斥锁有两个比较形象的例子可以解释两者的主要用途。 第一个是信号量: 使用信号量的最初目的是为了给共享 资源建立一个标志,该标志表示该共享资源被占用情况。这样,当一个任务在访问共享资源之前,可以先对这…...
C++基础——vector的详解与运用
vector的介绍 文档介绍 vector是表示可变大小数组的序列容器。就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,…...
const指针,星号判断方法
一 示例代码 1. const char *p // 指向常量的指针 2. char const *p // 指向常量的指针 3. char * const p // 指针常量二 判断方法 const在星号左边,指向常量的指针,指针p可修改。 const在星号右边,指针常量,指针p不可修改。...
移动摄像头专网需要解vlan,如何解决
🏆本文收录于「Bug调优」专栏,主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&…...
5.27周报
这两周邻近毕业故没有很多时间来学习课余内容,另外最近身体有些不舒服【偏头痛】,所以学的内容不多,包括SVM向量机和ResNet【不包括代码复现】 1.SVM支持向量机的大概内容 1、目的: 主要内容是如何找到分类的那条线【超平面】—…...
C-数据结构-树状存储的基本实现
/* 理解和记忆递归的关键在于把握递归的本质和函数调用的过程。递归函数在每次调用时会把当前状态压入调用栈,直到满足终止条件后开始回溯。理解基准条件和递归步骤:每个递归函数都需要有基准条件(如节点为空时返回),并…...
指纹识别经典图书、开源算法库、开源数据库
目录 1. 指纹识别书籍 1.1《精通Visual C指纹模式识别系统算法及实现》 1.2《Handbook of Fingerprint Recognition》 2. 指纹识别开源算法库 2.1 Hands on Fingerprint Recognition with OpenCV and Python 2.2 NIST Biometric Image Software (NBIS) 3. 指纹识别开源数…...
嵌入式之译码器
系列文章目录 译码器嵌入式之译码器 嵌入式之译码器 系列文章目录一、译码器定义二、常见类型的译码器三、工作原理 一、译码器定义 译码器(Decoder)是一种数字电路,其主要功能是从输入的编码信号中解码出特定的信息或控制信号。 译码器通常…...
分成sum接近的2个集合,返回相对小的sum
题目描述:给定一个正数数组arr,请把arr中所有的数分成两个集合,尽量让两个集合的累加和接近,返回最接近的情况下,较小集合的累加和sum。 way:选还是不选 //arr[index...]可以自由选择,返回累加和尽量接近…...
SpringBoot前置知识01-SPI接口
SpringBoot前置知识-SPI接口 介绍 Java中SPI是一种服务发现机制,或者说是一种思想,亦是一种约定。其实JDK中的JDBC就是使用了这种用思想,JDBC在JDK中只定义了接口,并没有实现类,连接什么数据库就要引入什么数据库的驱…...
数学建模--LaTeX的基本使用
目录 1.回顾 2.设置这个页眉和页脚 3.对于字体的相关设置 4.对于这个分级标题的设置 5.列表的使用 6.插入图片 1.回顾 (1)昨天我们了解到了这个latex的使用基本常识,以及这个宏包的概念,区域的划分,不同的代码代…...
linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...
Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...
自然语言处理——Transformer
自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息,但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN,但是…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...
动态 Web 开发技术入门篇
一、HTTP 协议核心 1.1 HTTP 基础 协议全称 :HyperText Transfer Protocol(超文本传输协议) 默认端口 :HTTP 使用 80 端口,HTTPS 使用 443 端口。 请求方法 : GET :用于获取资源,…...
虚拟电厂发展三大趋势:市场化、技术主导、车网互联
市场化:从政策驱动到多元盈利 政策全面赋能 2025年4月,国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》,首次明确虚拟电厂为“独立市场主体”,提出硬性目标:2027年全国调节能力≥2000万千瓦࿰…...
MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)
macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 🍺 最新版brew安装慢到怀疑人生?别怕,教你轻松起飞! 最近Homebrew更新至最新版,每次执行 brew 命令时都会自动从官方地址 https://formulae.…...
c++第七天 继承与派生2
这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分:派生类构造函数与析构函数 当创建一个派生类对象时,基类成员是如何初始化的? 1.当派生类对象创建的时候,基类成员的初始化顺序 …...
篇章二 论坛系统——系统设计
目录 2.系统设计 2.1 技术选型 2.2 设计数据库结构 2.2.1 数据库实体 1. 数据库设计 1.1 数据库名: forum db 1.2 表的设计 1.3 编写SQL 2.系统设计 2.1 技术选型 2.2 设计数据库结构 2.2.1 数据库实体 通过需求分析获得概念类并结合业务实现过程中的技术需要&#x…...
