详解Python和Rust中内存管理机制的实现与对比

 更新时间:2024年03月08日 14:06:07   作者:python慕遥  
Python和Rust都采用了垃圾收集(Garbage Collection)机制来管理内存,但它们各自的实现方式有很大的不同,下面就跟随小编一起来深入了解下二者的区别吧

大家好,内存管理是编程语言的基础,它确保着资源被有效利用,不同的编程语言采用不同的策略来管理内存。有些语言需要程序员手动管理内存,有些语言则自动化了内存管理过程。Python和Rust都采用了垃圾收集(Garbage Collection)机制来管理内存,但它们各自的实现方式有很大的不同。

1.Python:引用计数与分代式垃圾收集

Python使用称为“引用计数”的技术进行垃圾收集,每个对象都有一个计数器,跟踪对其的引用数量。当此计数达到零时,对象就会从内存中删除。

换句话说,每个内存中的对象都有一个关联的数字(称为“引用计数”),跟踪它被多少变量或其他对象指向。

import sys
 
# 创建对象x
x = [1, 2, 3]
 
# 获取x的引用计数(应该是1)
print("Reference Count of x:", sys.getrefcount(x) - 1)
 
# 创建x的引用
y = x
 
# 引用计数增加 1
print("Reference Count of x after y = x:", sys.getrefcount(x) - 1)
 
# 删除引用
del y
 
# 引用计数减少 1
print("Reference Count of x after del y:", sys.getrefcount(x) - 1)

输出:

Reference Count of x: 1
Reference Count of x after y = x: 2
Reference Count of x after del y: 1

Python采用称为“分代垃圾收集”的生成式方法,来进一步提高垃圾收集的效率。对象分为三个不同的“代”:

Generation 0:新对象

对象最初分配在第0代,这是其生命周期的第一阶段。

# 导入 gc(垃圾回收)模块
import gc
 
# 启用调试以打印垃圾收集信息
gc.set_debug(gc.DEBUG_STATS)
 
# 创建一个新的列表对象;该对象最初处于第 0 代
new_object = [1, 2, 3]
 
# 仅在第 0 代手动运行垃圾回收
gc.collect(0)

创建new_object时,它是一个新对象,会在第0代开始其生命

Generation 1:经历过一次垃圾回收周期的对象

在第0代垃圾回收周期中未被回收的对象会转移到第1代。

# 创建一个持久对象
persistent_object = {"key": "value"}
 
# 在第 0 代运行垃圾回收
gc.collect(0)
 
# 此时,"persistent_object "存活并进入第 1 代

在Python的分代式垃圾收集中,当一个对象首次建时,它会被放入第0代。每当对该代进行垃圾收集循环时,Python会寻找不再需要的对象(即引用计数为零的对象),以删除它们并释放内存。

如果像persistent\_object一样的对象在这个垃圾收集周期中存活下来,这意味着它仍在被引用或使用,它就会 "老化 "并进入下一代,在这种情况下是第1代。

这背后的原理是,新创建的对象更有可能是短命的,会很快被垃圾回收。另一方面,如果一个对象已经经历过一次垃圾回收周期,那么它就更有可能是长寿的,因此它会被转移到较老的一代,接受较少频率的检查。

由于persistent_object仍在使用中(在代码中的某个地方被引用),它的引用计数并不为零,因此它能在第0代垃圾回收过程中存活下来。

Generation 2:存活超过一个垃圾回收周期的对象

经过多次垃圾收集周期的对象最终会转到第2代。

# 创建另一个持久对象
very_persistent_object = (1, 2, 3)
 
# 对第 0 代和第 1 代进行垃圾回收
gc.collect(0)
gc.collect(1)
 
# 此时,"very_persistent_object "存活下来,并应进入第 2 代

在这里,very_persistent_object在第0代和第1代的垃圾回收中都能存活,因此它将转移到第2代。

实际上,开发者通常不需要手动控制或监控这些生成,Python 的垃圾回收器会自动处理,但了解它们的工作原理对调试和优化很有帮助。

2.Rust:基于所有权和借用的内存管理

Rust的内存管理方式与具有垃圾收集的语言(如Python)有着本质区别,它依赖于“所有权”和“借用”的概念来确保资源的安全管理。

2.1 所有权

在Rust中,每个值都有一个“所有者”,该值在其所有者存在时有效。当所有者超出范围时,该值及其资源会被自动释放,这样就不需要单独的垃圾回收过程了。

以下是个示例:

fn main() {
    let s1 = String::from("hello");  // s1是值"hello"的所有者
    let s2 = s1;  // s1的所有权被传递给s2
 
    // println!("{}", s1);  // 这将导致错误,因为s1不再拥有该值
    println!("{}", s2);  // 这是可以的,s2现在是所有者
}  // s2超出范围,“hello”被释放

在本例中,s1最初拥有字符串 "hello",然后所有权转移到s2。当s2在main()的结尾超出范围时,字符串"hello"会被自动释放。

2.2 借用

有时,需要访问一个值而不需要取得其所有权,因此 Rust 允许 "借用",可以借用一个可变或不可变的引用值。

不可变借用:

fn main() {
    let s1 = String::from("hello");
    let len = calculate_length(&s1);  // &s1借用s1而不拥有它
    println!("'{}'的长度为{}.", s1, len);
}
 
fn calculate_length(s: &String) -> usize {
    s.len()
}

可变借用:

fn main() {
    let mut s1 = String::from("hello");
    change_string(&mut s1);  // &mut s1以可变引用形式借用s1
    println!("{}", s1);
}
 
fn change_string(s: &mut String) {
    s.push_str(", world");
}

在这些示例中,&s1和&mut s1借用了值,但没有取得所有权,从而允许 s1在函数调用后继续使用。

Rust 方法的主要优势在于,它可以精确控制代码的哪些部分可以使用、修改或取消分配值,从而使程序更安全、更高效,而无需进行垃圾收集。

到此这篇关于详解Python和Rust中内存管理机制的实现与对比的文章就介绍到这了,更多相关Python内存管理机制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Python OpenCV阈值处理详解

    Python OpenCV阈值处理详解

    阈值处理是一种简单、有效的将图像划分为前景和背景的方法。图像分割通常用于根据对象的某些属性(例如,颜色、边缘或直方图)从背景中提取对象。本文将为大家详细介绍OpenCV中的阈值处理,需要的可以参考一下
    2022-02-02
  • Python 创建TCP服务器的方法

    Python 创建TCP服务器的方法

    这篇文章主要介绍了Python 创建TCP服务器的方法,文中讲解非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下
    2020-07-07
  • 实例探究Python以并发方式编写高性能端口扫描器的方法

    实例探究Python以并发方式编写高性能端口扫描器的方法

    端口扫描器就是向一批端口上发送请求来检测端口是否打开的程序,这里我们以实例探究Python以并发方式编写高性能端口扫描器的方法
    2016-06-06
  • Python实现的视频播放器功能完整示例

    Python实现的视频播放器功能完整示例

    这篇文章主要介绍了Python实现的视频播放器功能,结合完整实例形式分析了Python基于pyglet库实现视频播放功能的相关操作技巧,需要的朋友可以参考下
    2018-02-02
  • python深度学习之多标签分类器及pytorch实现源码

    python深度学习之多标签分类器及pytorch实现源码

    这篇文章主要为大家介绍了python深度学习之多标签分类器的使用说明及pytorch的实现源码,有需要的朋友可以借鉴参考下,希望能够有所帮助
    2022-01-01
  • pygame 键盘事件的实践

    pygame 键盘事件的实践

    本文主要介绍了pygame 键盘事件,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-11-11
  • Python进程间通信方式

    Python进程间通信方式

    这篇文章主要介绍了Python进程间通信方式,进程彼此之间互相隔离,要实现进程间通信,主要通过队列方式,下文更多详细内容,需要的小伙伴可以参考一下
    2022-03-03
  • Pytorch使用MNIST数据集实现CGAN和生成指定的数字方式

    Pytorch使用MNIST数据集实现CGAN和生成指定的数字方式

    今天小编就为大家分享一篇Pytorch使用MNIST数据集实现CGAN和生成指定的数字方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-01-01
  • 如何基于Python实现电子邮件的发送

    如何基于Python实现电子邮件的发送

    这篇文章主要介绍了如何基于Python实现电子邮件的发送,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12
  • 关于pip安装opencv-python遇到的问题

    关于pip安装opencv-python遇到的问题

    这篇文章主要介绍了关于pip安装opencv-python遇到的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02

最新评论