文章采集调用(引用计数策略和垃圾收集策略都属于资源的自动化管理)

优采云 发布时间: 2021-09-21 05:01

  文章采集调用(引用计数策略和垃圾收集策略都属于资源的自动化管理)

  源链接:

  从本质上讲,引用计数策略和垃圾采集策略都属于资源的自动管理。所谓的自动管理是指逻辑层不知道资源何时释放,而是依靠底层库来维持资源的生命周期

  手动管理可以准确地了解资源的生命周期,并在准确的位置回收资源。在C++中,析构函数指定用于删除的资源,编译器生成的代码自动析构函数基类和成员变量

  因此,为C++编写垃圾采集器与手动管理资源并不冲突。几乎所有大型C++项目都使用自动化管理,但它使用引用计数策略,而不是垃圾采集。也就是说,长期以来,我们采用C++或C语言,将人工管理和自动管理相结合来构建系统。无论是使用引用计数还是垃圾采集,我们仍然可以在软件实现的细节中管理手动管理

  为什么使用自动资源生命周期管理

  让我们看一下面向对象。如果一切都是一个物体,那么每个物体都应该对自己的生命负责。我们可以直接准确地确定死亡时间。不幸的是,很多东西都不是纯对象。最重要的是对象容器。除了它们自己的属性外,它们还维护对一组类似对象的引用

  一个对象可以被多个容器引用,这使得容器不同于猫和狗的对象实体。因为容器指的是一个事物,它并不意味着它是容器的一部分(有时可以,有时不能)。当我们想把整个世界分成物体,所有原子都分成各个层次的物体时,我们会发现,物体无法提取的概念总数为零。引用而不是拥有是不可避免的

  面向对象的本质是从许多对象中提取共性,并将它们一起处理。这样,各种容器的使用是不可避免的

  同样,该对象不知道他是否可以宣布死亡。除非您知道自己与其他对象的关系(此关系不是对象)。资源可以是对象,而自动管理就是管理这些对象和对象之间的关系

  引用计数是最容易实现的解决方案:记录对象被引用的次数,而不具体记录引用对象的人。这样,建立和取消引用的成本就降低了。然而,也有得失。在引用计数的过程中,我们也丢失了重要的信息:谁引用了我们自己。因此,在处理间接引用时,引用计数的成本更高

  物体死亡的判断是物体是否与世界有直接或间接的联系。因此,即使一个对象被另一个对象直接引用,该对象也可能不存在。为了解决这个问题,使用引用计数的系统必须在与世界断开连接时通知与其关联的对象。目标销毁成本的增加是参考计数策略的短板

  物体的破坏频率取决于物体的平均寿命。一方面,对象的生存时间受对象粒度的影响。对象粒度越细,对象的平均生存时间越短(虽然表面上没有直接联系,但在实际设计中往往会导致这种结果);另一方面,我们通常将容器和引用关系实现为一个对象(概念上,它不应该是一个对象)。例如,许多自动维护引用计数的智能指针是一个小容器,其中收录对对象的唯一引用,并且它是作为一个小对象实现的

  通常,对象本身的性质不会随其在内存空间中的位置而改变。但是,引用关系(通常用指针实现)与内存地址有关。C++缺少用于在内存中移动对象的语义表达式。等效的方法是在一个新的内存块中复制和构造一个新对象,并销毁原创对象

  另一方面,在程序的运行序列中,由函数调用引起的堆栈上的嵌套作用域也可以视为容器。机器指令通过这些作用域,临时构造的对象引用(智能指针)被放置在这些作用域中。函数调用越频繁,创建和销毁这些作用域的频率就越高

  因此,C++必须依赖大量的内联函数来让编译器知道更多的上下文信息,从而减少创建和销毁小对象(智能指针)的负担。STL库也必须优化。例如,在STL端口中,pod类型被视为特例。不幸的是,智能指针不是pod,这使得编译器足够智能,可以在执行序列中合并引用的加减,这太困难了(考虑到多线程因素,除非编译器知道线程信息,否则几乎不可能实现)

  在实现面向对象编程方面,C++比C更方便。其中之一是,当描述一个对象是另一个对象的一部分时,可以通过构造和析构函数机制自动维护相关部分的生命周期。但它在语言中未能解决的是,当两者之间只有一个参照关系时,如何处理生命周期。对于前者,我们几乎只有简洁明了的解决方案;后者可以根据实际需要有多种选择,而C++在语言级别上没有提供一致的解决方案。不幸的是,C++始终能够提供一个简洁且易于使用的通用GC库。我们都喜欢比较容易实现的参考计数方案。这一结果与具体实现的复杂性有关。毕竟,在实现GC时,C缺乏必要的语言支持(C++是在实现级别从C开发的)

  让我们看看垃圾采集。更成熟的算法基于标记移除(或标记排序)或其变体。简而言之,采集器框架记录对象之间的关系(存储这些联系信息的位置并不重要。它可以位于对象的内存布局空间中,也可以位于独立的位置。关键是采集器可以访问这些信息)。确定世界的根,定期从此根遍历世界,标记关联的对象,最后回收未标记的对象

  从算法的角度来看,建立对象之间连接的时间开销和参考计数的时间开销在数量级上是相同的,两者都是o(1))。然而,在实际实施中,前者的成本通常较高。空间成本也略高,但在数量级上没有差别

  销毁GC管理的对象的成本要低得多。它不需要通知与其关联的对象

  这就是为什么许多使用GC的软件有时比使用引用计数的软件更高效的原因

  然而,GC在标记过程中需要额外的时间成本。完成一个完整的清洁过程必须穿越世界上每一个有生命的物体。成本为O(n),n随着对象总数的增加而增加。因此,我们应该减少GC管理的对象数量。在这方面,手工管理仍然是有意义的。也就是说,当一个对象显然是另一个对象的一部分时,可以考虑手动管理

  另一个缺点是,在实现时,我们经常将对象之间的关联信息放在对象本身的内存布局空间中。在这个世界上遍历对象意味着访问所有对象的内存。当虚拟内存空间大于实际物理内存空间时,表示页面交换。我认为,在很大程度上,Java或c#等语言是一起使用的。构建的庞大系统有时运行缓慢,这是根本原因。当然,这些是可以改进的。这不是算法本身的问题

  可以说,GC(垃圾采集)将RC(引用计数)中短期对象的销毁成本转移到一次性标记移除过程中。这是逻辑处理和资源管理的正交分解。随着硬件的进步(如多核开发),这种分解问题将更容易提高性能,但是,这种优势在小型软件或独立模块中并不明显。相反,GC本身的复杂性远远高于RC,这将成为它的弱点

  对于不需要面向对象软件,甚至不需要自动资源管理的软件,GC或RC是无用的

  我做的简单垃圾采集器只是想在为C或C++语言构建软件时做一些简单的尝试并做出更多的选择

  从本质上讲,引用计数策略和垃圾采集策略都属于资源的自动管理。所谓自动管理是指逻辑层不知道资源何时释放,而是依赖底层库来维护资源的生命周期

  在C++中,析构函数指定用于删除的资源,编译器生成的代码自动构造基类和成员变量

  因此,为C++编写垃圾采集器与手动资源管理没有冲突。自动化管理在一个系统中使用

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线