Mojo值的生命周期(Death of a value)详解

server/2024/10/21 7:49:15/

一旦不再使用某个值/对象,Mojo 就会将其销毁。Mojo 不会等到 代码块结束(甚至不会等到表达式结束)才销毁未使用的值。它使用在每个子表达式之后运行的“尽快”(ASAP)销毁策略来销毁值。即使在像这样的表达式中a+b+c+d,Mojo 也会在不再需要中间值时立即销毁它们。

Mojo 使用静态编译器分析来查找值最后一次使用的位置。然后,Mojo 立即结束该值的生命周期并调用析__del__() 构函数来执行该类型的任何必要清理。

例如,请注意__del__()每个实例的析构函数被调用的时间MyPet:

@value
struct MyPet:var name: Stringvar age: Intfn __del__(owned self):print("Destruct", self.name)fn pets():var a = MyPet("Loki", 4)var b = MyPet("Sylvie", 2)print(a.name)# a.__del__() runs here for "Loki"a = MyPet("Charlie", 8)# a.__del__() runs immediately because "Charlie" is never usedprint(b.name)# b.__del__() runs herepets()

输出为:

Loki
Destruct Loki
Destruct Charlie
Sylvie
Destruct Sylvie

请注意,每个值的初始化都与对析构函数的调用相匹配,并且a实际上会被销毁多次 - 每次收到新值时都会销毁一次。

大多数结构不需要自定义析构函数,如果你没有定义析构函数,Mojo 会自动添加一个无操作析构函数。

默认销毁行为


您可能想知道 Mojo 如何在没有自定义析构函数的情况下销毁类型,或者为什么无操作析构函数很有用。如果类型只是字段的集合(如示例)MyPet,则 Mojo 只需销毁字段:MyPet不会动态分配内存或使用任何长期存在的资源(如文件句柄)。当值被销毁时,对于MyPet的销毁无需采取任何特殊操作。

查看各个字段,MyPet包括一个Int和String。

Mojo的Int称其为简单类型。它是静态大小位数。Mojo 确切知道它有多大,因此可以重复使用这些位来存储其他内容。

Mojo的String值稍微复杂一些。Mojo 字符串是可变的。该 String对象有一个内部缓冲区 - 一个 List字段,它保存组成字符串的字符。AList将其内容存储在堆上动态分配的内存中,因此字符串可以增大或缩小。字符串本身没有任何特殊的析构函数逻辑,但当 Mojo 销毁字符串时,它会调用该字段的析构函数 List,从而取消分配内存。

由于String和Int不需要任何自定义析构函数逻辑,它们都具有无操作析构函数:字面意思是__del__()不执行任何操作的方法。这似乎毫无意义,但这意味着 Mojo 可以在任何值的生命周期结束时调用其析构函数。这使得编写通用容器和算法变得更加容易。

ASAP 销毁的好处


与其他语言类似,Mojo 遵循对象/值在构造函数(init())中获取资源并在析构函数(del())中释放资源的原则。但是,Mojo 的 ASAP 销毁比基于范围的销毁具有一些优势(例如 C++ RAII 模式,它等到代码范围结束后才销毁值):

  • 最后一次使用时立即销毁值与“移动”优化完美结合,将“复制 + 删除”对转换为“移动”操作。
  • 在 C++ 中,在作用域末尾销毁值对于某些常见模式(如尾部递归)而言是有问题的,因为析构函数调用发生在尾部调用之后。对于某些函数式编程模式而言,这可能是一个严重的性能和内存问题,但在 Mojo 中则不是问题,因为析构函数调用始终发生在尾部调用之前。

此外,Mojo 的 ASAP 销毁在 Python 风格的def 函数中效果很好。这是因为 Python 实际上不提供超出函数范围的范围,因此 Python 垃圾收集器清理资源的频率比基于范围的销毁策略更高。但是,Mojo 不使用垃圾收集器,因此 ASAP 销毁策略提供的销毁保证比 Python 更细粒度。

Mojo 的销毁策略与 Rust 和 Swift 的工作方式更相似,因为它们都具有强大的值所有权跟踪功能并提供内存安全性。一个区别是 Rust 和 Swift 需要使用动态“删除标志” ——它们维护隐藏的影子变量来跟踪值的状态以提供安全性。这些通常会被优化掉,但 Mojo 方法完全消除了这种开销,


http://www.ppmy.cn/server/95820.html

相关文章

Flink学习之Flink SQL

Flink SQL 1、SQL客户端 1.1 基本使用 启动yarn-session yarn-session.sh -d启动Flink SQL客户端 sql-client.sh--退出客户端 exit;测试 重启SQL客户端之后,需要重新建表 -- 构建Kafka Source -- 无界流 drop table if exists students_kafka_source; CREATE TABL…

Python爬虫技术 第33节 未来趋势和技术发展

网络爬虫(Web crawler)是一种自动化的程序或脚本,用于遍历互联网上的网页并收集所需的数据。爬虫技术在许多领域都有广泛的应用,从搜索引擎到数据分析、市场研究、竞争情报等。 爬虫技术的基础 基本原理: URL管理&…

ARM 架构硬件新趋势:嵌入式领域的未来

目录 目录 一、ARM 架构概述 二、新趋势一:AI 加速器集成 三、新趋势二:更高效的电源管理 四、新趋势三:安全性增强 五、结语 随着物联网 (IoT) 和边缘计算的发展,ARM 架构在嵌入式系统中的应用越来越广泛。从智能手机到智能…

【转行大模型 01】大数据已死?AI当道!我为何想转战大模型

作为一名经验丰富的大数据开发工程师,我最近决定扩展自己的职业方向,转向大模型应用开发。这个决定源于对技术趋势的观察、对个人发展的思考,以及对我们行业未来的预判。让我从一个大数据工程师的视角,逐步分析这个决定背后的逻辑…

MySQL事务,锁,MVCC总结

mysql中最重要的就是事务,其四大特性让我们维持了数据的平衡,一致。那么事务究竟是什么,与什么相关,他的使用步骤,以及使用过程中我们会遇到什么问题呢?下面我们一起学习交流! 1.MySQL的存储引擎&#xff…

算法【构建前缀信息解决子数组问题】

本文需要对掌握哈希表的用法。 构建某个前缀信息比如最早出现、最晚出现、出现次数等,是很常见的技巧。除此之外,还有很多种类的前缀信息可以构建出来,解决很多子数组相关问题。下面通过几个题目加深对构建前缀信息这个方法的理解。 题目一 …

《深入浅出WPF》学习笔记六.手动实现Mvvm

《深入浅出WPF》学习笔记六.手动实现Mvvm demo的层级结构,Mvvm常用项目结构 依赖属性基类实现 具体底层原理后续学习中再探讨,可以粗浅理解为,有一个全局对象使用list或者dic监听所有依赖属性,当一个依赖属性变化引发通知时,就会遍历查询对应的字典,通知View层进行…

135. 分发糖果【 力扣(LeetCode) 】

一、题目描述 n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。 你需要按照以下要求,给这些孩子分发糖果: 每个孩子至少分配到 1 个糖果。相邻两个孩子评分更高的孩子会获得更多的糖果。 请你给每个孩子分发糖果,计算并返回…