perl5和perl6_垃圾收集在Perl 6

perl5和perl6

在本系列的第一篇有关将Perl 5代码迁移到Perl 6的文章中,我们研究了在移植代码时可能遇到的一些问题。 在第二篇文章中,我们将介绍Perl 6中垃圾回收的不同之处。

在Perl 6中没有及时销毁对象。这种启示通常会给习惯于Perl 5中销毁对象语义的人们带来很大的震撼。但是不用担心,Perl 6中还有其他方法可以实现相同的行为,尽管需要开发者多加思考。 首先让我们研究一下Perl 5中的情况。

参考计数

在Perl 5中,可以通过引用计数来及时销毁“超出范围”的对象。 在Perl 5中创建内容时,它的引用计数为1或更大,从而使它保持活动状态。 在最简单的情况下,它看起来像这样:


   
   
{
    my $a = 42 ;   # reference count of $a = 1, because lives in lexical pad
}
# lexical pad is gone, reference count to 0

在Perl 5中,如果该值是一个对象(又名有福),则将在其上调用DESTROY方法。


   
   
{
    my $a = Foo -> new ;
}
# $a->DESTROY called

如果不涉及外部资源,及时销毁只是管理程序使用的内存的另一种方法。 而且,作为程序员,您无需关心如何以及何时回收这些东西。 话虽如此,如果您需要处理外部资源(例如数据库句柄)(数据库服务器通常只提供有限的数量),及时销毁是一个非常不错的功能。 引用计数可以提供这一点。

但是,引用计数有几个缺点。 Perl 5核心开发人员花了很多年才能使引用计数正常工作。 而且,如果您在XS中工作,则始终需要注意引用计数,以防止内存泄漏或过早破坏。

在多线程环境中,保持事物同步变得更加困难,因为您不想丢失对同时来自多个线程的引用的任何更新(因为这将导致内存泄漏和/或外部资源无法释放) 。 为了避免这种情况,将需要某种锁定或原子更新,但都不便宜。

请注意,与诸如C之类的编程语言中的线程相比,Perl 5 ithreads更像是在解释器之间具有未共享内存的内存中派生。因此,它的引用计数仍然不需要任何锁定。

引用计数还具有一个基本的缺点,即如果两个对象包含彼此的引用,则它们将永远不会被破坏,因为它们会将彼此的引用计数保持在0(循环引用)以上。 在实践中,这通常会更深入,更像是A -> B -> C -> A ,其中A,B和C彼此保持生命。

弱引用的概念是为了在Perl 5中规避这些情况而开发的。尽管这可以解决循环引用问题,但是它具有性能影响,并且不能解决首先具有(并找到)循环引用的问题。 你必须能够找出一个弱引用可以以最佳的方式使用; 否则,可能会导致不必要的对象过早破坏。

可达性分析

由于Perl 6的内核是多线程的,因此在很早的时候就决定引用计数在性能和维护方面都是有问题的。 相反,当需要更多内存并且可以安全删除对象时,会将对象从内存中逐出。

可以像在Perl 5中一样创建DESTROY方法。但是您无法确定何时(如果有)将调用该方法。

无需过多讨论 ,Perl 6中的对象仅在启动垃圾回收运行时(例如,达到某个内存限制时)才被销毁。 只有这样,如果对象不能再通过在存储器中的其它物体接触到它有一个DESTROY方法,将它称为只是之前被取出物体。

程序退出时,Perl 6不会进行垃圾回收。 适用的相位器 (例如LEAVEEND被调用,但是除了(间接地)由相位器中运行的代码启动的垃圾回收之外,不会执行任何垃圾回收。

如果始终需要有序地关闭程序所使用的外部资源(例如数据库句柄),则可以使用移相器来确保以适当,及时的方式释放外部资源。

例如,您可以使用END相位器(在Perl 5中称为END块)在程序退出时(无论出于何种原因)与数据库正确断开连接:


   
   
my $dbh = DBIish . connect ( ... ) or die "Couldn't connect" ;
END $dbh . disconnect ;

请注意, END相位器在Perl 6中不需要块(如{ ... } )。如果没有,则相位器中的代码与周围的代码共享词汇垫(lexpad)。

上面的代码中有一个缺陷:如果程序建立数据库连接之前退出或者由于某种原因数据库连接失败,它将仍然尝试对$dbh任何内容调用.disconnect方法,这将导致执行错误。 然而, 一个简单的成语,以规避在Perl 6的这种情况下使用

 END . disconnect with $dbh ; 

只有定义了给定值(通常是实例化的对象),然后将其主题化为$_with的后缀才匹配。 .disconnect$_.disconnect .disconnect的缩写。

如果您希望在退出特定范围时清理外部资源,则可以在该范围内使用LEAVE移相器。


   
   
if DBIish . connect ( ... ) -> $dbh {
    LEAVE $dbh . disconnect ;   # no need for `with` here
    # do your stuff with the database
}
else {
    say "Could not do the stuff that needed to be done" ;
}

只要剩下if的范围,任何LEAVE移相器都会执行。 因此,只要代码在该范围内运行,数据库资源就会被释放。

摘要

尽管Perl 6没有像Perl 5用户那样及时销毁对象,但它确实具有易于使用的替代方法来确保外部资源的管理,这与Perl 5中的类似。

翻译自: https://opensource.com/article/18/8/garbage-collection-perl-6

perl5和perl6

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值