首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在全局启用发生检查时,Prolog是否需要GC?

在全局启用发生检查时,Prolog是否需要GC?
EN

Stack Overflow用户
提问于 2020-11-15 02:38:08
回答 3查看 292关注 0票数 7

据我所知,使用声音统一,SLD分辨率不应该创建循环数据结构(这是正确的吗?)

如果是这样,理论上可以实现Prolog,使其不需要垃圾收集(GC)。但话又说回来,人们可能不会。

  • 基于WAM的Prolog实现是这样的吗?
  • 是这样的吗?(我相信这不是基于WAM的)在SWI中禁用GC安全吗?

具体地说:

代码语言:javascript
复制
:- set_prolog_flag(occurs_check, true).
:- set_prolog_flag(gc, false). /* is this safe? */
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-11-15 15:36:31

创建循环术语远非唯一能够在Prolog中创建垃圾(如在垃圾收集中)的操作(也值得注意的是,并非所有Prolog系统都提供对循环术语的全面支持,但其中大多数支持某种形式的垃圾收集)。

例如,假设您的代码中有从一个数字到一个原子的以下调用序列:

代码语言:javascript
复制
...,
number_codes(Number, Codes),
atom_codes(Atom, Codes),
...

在这里,Codes是一个应该被垃圾收集的临时列表。另一个例子是,假设您调用setof/3是为了获得一个有序的结果列表,其中您只对前两个结果感兴趣:

代码语言:javascript
复制
...,
setof(C, x(X), [X1, X2| _]),
...

你刚刚创建了另一个临时列表。或者您忘记了sub_atom/5,决定使用atom_concat/3检查原子的前缀:

代码语言:javascript
复制
...,
atom_concat(Prefix, _, Atom),
...

第二个参数是您不关心的原子后缀(因此是匿名变量),它是您刚刚创建的临时原子。但并非所有Prolog系统都提供原子垃圾收集器,这可能导致长期运行的应用程序出现麻烦。

但是,即使您认为您已经仔细编写了代码以避免创建临时术语,Prolog系统在运行代码时仍然可能会创建垃圾。Prolog系统为不同的目的使用不同的内存区域,并且操作可能需要在不同的内存区域之间临时复制内存片段,这取决于实现。Prolog系统可能是用一种语言编写的,例如Java,最终可能会处理这些垃圾。但是它很可能是用C或C++编写的,并且在内部使用某种类型的垃圾收集。更不用说Prolog系统可能会占用一大块内存来证明查询,然后在查询结束后恢复该内存。

票数 8
EN

Stack Overflow用户

发布于 2020-11-15 09:36:02

嗯,有些东西必须释放多引用内存,其中存在引用,可以在计算的任何步骤中删除。这是独立于结构是否循环的情况。

考虑变量AB在内存中命名相同的结构(它们“命名相同的术语”)。该结构是从两个地方引用。假设定义B的谓词成功或失败。Prolog处理器不能仅仅释放该结构:它仍然是从A引用的。这意味着您至少需要参考计数,以确保您不会太早释放内存。这是一个计算垃圾收集器的引用。

我不知道在任何特定的Prolog实现中实现了什么样的垃圾收集(有许多方法,有些更适合Prolog .在一个不完全无关的上下文中,25年的Java已经创建了所有这些),但是您需要使用一个,而不一定是一个计算引用的引用。

(循环结构只适用于垃圾收集,因为引用计数垃圾收集算法无法释放循环结构,因为循环中的所有单元格都有至少1的引用计数。)

(另外,IMHO,而不是信任-一种编程语言,您必须自己调用free格林斯夫第十法则可能有一个变体(“任何足够复杂的C或Fortran程序都包含一个特定的、非正式指定的、充满错误的、缓慢实现公共Lisp一半的程序”)。在这种情况下,任何用编程语言编写的程序(您必须自己调用free )都包含垃圾收集算法的一个临时的、非正式指定的、充满错误的缓慢实现。

(OTOH,Rust似乎是一种中间路,它将一些精力转移到开发人员身上,但它的优点是能够在变量超出作用域时决定是否释放内存。但锈病并不是Prolog。)

票数 4
EN

Stack Overflow用户

发布于 2021-03-03 21:14:38

在这里这样是安全的:

代码语言:javascript
复制
:- set_prolog_flag(gc, false).

但是,如果Prolog系统有垃圾收集,那么关闭它可能不是一个好主意,因为即使发生了check设置为true,仍然可以通过临时结果进行垃圾处理。并且连续清除垃圾可以提高代码的局部性,例如,您的内存被缓存丢失所破坏的更少:

代码语言:javascript
复制
p(X,Y) :- q(X,Z), r(Z,Y).

变量Z可能指向某些只暂时需要的Prolog项。大多数现代Prolog系统都可以通过所谓的环境修整来删除这样的Prolog术语。

但是发生的检查打开了一种特殊类型的垃圾收集的路径。也就是说,由于不能出现更多的循环项,所以可以使用引用计数。一个古老的Prolog系统,有参考计数,就是这里的野兽:

xpProlog:高性能扩展纯Prolog - Lüdemann,1988年

https://open.library.ubc.ca/media/download/pdf/831/1.0051961/1

此外,Jekejeke还在做参考计数。引用计数的一个问题是属性变量,尽管如此,它还是可以创建一个循环项,例如,如下所示的冻结/2会通过冻结目标创建一个循环,返回到变量:

代码语言:javascript
复制
?- freeze(X, (write(X), nl)).

编辑04.09.2021:

可能还需要垃圾收集的是setarg/3。

可以创建不太容易被

参考计数。

代码语言:javascript
复制
?- X = f(0), setarg(1,X,X).
X = f(X).

由于setarg/3是可回溯的,循环就会消失。

回溯,至少我想是这样。但这种循环可能仍会令人烦恼。

当我们陷入回溯和内存耗尽的时候。

或者循环可能不会通过回溯而消失,因为我们

使用非回溯版本nb_setarg/3。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64840715

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档