据我所知,使用声音统一,SLD分辨率不应该创建循环数据结构(这是正确的吗?)
如果是这样,理论上可以实现Prolog,使其不需要垃圾收集(GC)。但话又说回来,人们可能不会。
具体地说:
:- set_prolog_flag(occurs_check, true).
:- set_prolog_flag(gc, false). /* is this safe? */发布于 2020-11-15 15:36:31
创建循环术语远非唯一能够在Prolog中创建垃圾(如在垃圾收集中)的操作(也值得注意的是,并非所有Prolog系统都提供对循环术语的全面支持,但其中大多数支持某种形式的垃圾收集)。
例如,假设您的代码中有从一个数字到一个原子的以下调用序列:
...,
number_codes(Number, Codes),
atom_codes(Atom, Codes),
...在这里,Codes是一个应该被垃圾收集的临时列表。另一个例子是,假设您调用setof/3是为了获得一个有序的结果列表,其中您只对前两个结果感兴趣:
...,
setof(C, x(X), [X1, X2| _]),
...你刚刚创建了另一个临时列表。或者您忘记了sub_atom/5,决定使用atom_concat/3检查原子的前缀:
...,
atom_concat(Prefix, _, Atom),
...第二个参数是您不关心的原子后缀(因此是匿名变量),它是您刚刚创建的临时原子。但并非所有Prolog系统都提供原子垃圾收集器,这可能导致长期运行的应用程序出现麻烦。
但是,即使您认为您已经仔细编写了代码以避免创建临时术语,Prolog系统在运行代码时仍然可能会创建垃圾。Prolog系统为不同的目的使用不同的内存区域,并且操作可能需要在不同的内存区域之间临时复制内存片段,这取决于实现。Prolog系统可能是用一种语言编写的,例如Java,最终可能会处理这些垃圾。但是它很可能是用C或C++编写的,并且在内部使用某种类型的垃圾收集。更不用说Prolog系统可能会占用一大块内存来证明查询,然后在查询结束后恢复该内存。
发布于 2020-11-15 09:36:02
嗯,有些东西必须释放多引用内存,其中存在引用,可以在计算的任何步骤中删除。这是独立于结构是否循环的情况。
考虑变量A和B在内存中命名相同的结构(它们“命名相同的术语”)。该结构是从两个地方引用。假设定义B的谓词成功或失败。Prolog处理器不能仅仅释放该结构:它仍然是从A引用的。这意味着您至少需要参考计数,以确保您不会太早释放内存。这是一个计算垃圾收集器的引用。
我不知道在任何特定的Prolog实现中实现了什么样的垃圾收集(有许多方法,有些更适合Prolog .在一个不完全无关的上下文中,25年的Java已经创建了所有这些),但是您需要使用一个,而不一定是一个计算引用的引用。
(循环结构只适用于垃圾收集,因为引用计数垃圾收集算法无法释放循环结构,因为循环中的所有单元格都有至少1的引用计数。)
(另外,IMHO,而不是信任-一种编程语言,您必须自己调用free。格林斯夫第十法则可能有一个变体(“任何足够复杂的C或Fortran程序都包含一个特定的、非正式指定的、充满错误的、缓慢实现公共Lisp一半的程序”)。在这种情况下,任何用编程语言编写的程序(您必须自己调用free )都包含垃圾收集算法的一个临时的、非正式指定的、充满错误的缓慢实现。
(OTOH,Rust似乎是一种中间路,它将一些精力转移到开发人员身上,但它的优点是能够在变量超出作用域时决定是否释放内存。但锈病并不是Prolog。)
发布于 2021-03-03 21:14:38
在这里这样是安全的:
:- set_prolog_flag(gc, false).但是,如果Prolog系统有垃圾收集,那么关闭它可能不是一个好主意,因为即使发生了check设置为true,仍然可以通过临时结果进行垃圾处理。并且连续清除垃圾可以提高代码的局部性,例如,您的内存被缓存丢失所破坏的更少:
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会通过冻结目标创建一个循环,返回到变量:
?- freeze(X, (write(X), nl)).编辑04.09.2021:
可能还需要垃圾收集的是setarg/3。
可以创建不太容易被
参考计数。
?- X = f(0), setarg(1,X,X).
X = f(X).由于setarg/3是可回溯的,循环就会消失。
回溯,至少我想是这样。但这种循环可能仍会令人烦恼。
当我们陷入回溯和内存耗尽的时候。
或者循环可能不会通过回溯而消失,因为我们
使用非回溯版本nb_setarg/3。
https://stackoverflow.com/questions/64840715
复制相似问题