哈希表的可疑SBCL垃圾收集错误



我在Ubuntu 18.04上使用SBCL 1.4.5。

SBCL中的垃圾收集器似乎没有正确释放绑定到具有符号键和值的哈希表的内存。有趣的是,当键和值是整数时,垃圾收集工作得很好。

例如,以下程序工作正常:

(defun copy-hash-table (hash)
(let ((h (make-hash-table
:test (hash-table-test hash)
:rehash-size (hash-table-rehash-size hash)
:rehash-threshold (hash-table-rehash-threshold hash)
:size (hash-table-size hash))))
(loop for key being the hash-keys of hash
using (hash-value value)
do
(setf (gethash key h) value)
finally (return h))))
(defun make-integer-input ()
(loop
with hash1 = (make-hash-table) and hash2 =  (make-hash-table)
for i from 0 to 500
do
(setf (gethash (random 100) hash1) (random 100))
(setf (gethash (random 100) hash2) (random 100))
finally
(return (list hash1 hash2))))
(defun do-integer-work (hash1 hash2)
(loop
for i being the hash-keys of hash1
for j being the hash-keys of hash2
do
(remhash i hash1)
(setf (gethash i hash1) (random 100))
(remhash j hash2)
(setf (gethash j hash2) (random 100)))
(values hash1 hash2))
(defun hash-worker (list-obj)
(loop
with next
for i from 1 to 50000
do
(multiple-value-bind (new-hash1 new-hash2)
(do-integer-work (copy-hash-table (first list-obj)) (copy-hash-table (second list-obj)))
(setq next (list new-hash1 new-hash2))
(if (> (random 100) 50)
(setq list-obj next)))))

我通过调用(hash-worker (make-integer-input))来运行这个程序。顶级函数hash-worker接收两个哈希表的列表,并处理do-integer-work中哈希表的副本。然后,helper函数输出保存在new-hash1new-hash2中的两个修改后的哈希表。然后系统随机决定是否保留修改后的哈希表。

do-integer-work助手函数按顺序删除哈希表的键,并用新的随机值重新提交它们。

当这个程序运行时,我观察到在程序运行期间内存消耗基本上是恒定的。当我在带有符号键和值的哈希表上运行姐妹程序时,情况并非如此。

(defun copy-hash-table (hash)
(let ((h (make-hash-table
:test (hash-table-test hash)
:rehash-size (hash-table-rehash-size hash)
:rehash-threshold (hash-table-rehash-threshold hash)
:size (hash-table-size hash))))
(loop for key being the hash-keys of hash
using (hash-value value)
do
(setf (gethash key h) value)
finally (return h))))
(defun make-symbol-input ()
(loop
with hash1 = (make-hash-table) and hash2 =  (make-hash-table)
for i from 0 to 500
do
(setf (gethash (gentemp) hash1) (gentemp))
(setf (gethash (gentemp) hash2) (gentemp))
finally
(return (list hash1 hash2))))
(defun do-symbol-work (hash1 hash2)
(loop
for i being the hash-keys of hash1
for j being the hash-keys of hash2
do
(remhash i hash1)
(setf (gethash i hash1) (gentemp))
(remhash j hash2)
(setf (gethash j hash2) (gentemp)))
(values hash1 hash2))
(defun hash-worker (list-obj)
(loop
with next
for i from 1 to 50000
do
(multiple-value-bind (new-hash1 new-hash2)
(do-symbol-work (copy-hash-table (first list-obj)) (copy-hash-table (second list-obj)))
(setq next (list new-hash1 new-hash2))
(if (> (random 100) 50)
(setq list-obj next)))))

我运行了这个名为(hash-worker (make-symbol-input))的程序。这个程序的不同之处在于,顶级函数调用do-symbol-work。当这个程序运行时,我观察到系统的内存使用量稳步增加,直到我的机器内存耗尽。

这是SBCL中已知的错误吗?如果是,有解决方法吗?

您使用的是gentemp,它实习它创建的符号。这样的符号不能是GCd,因为它们被它们的包引用了。因此,你正在生成大量的内部符号,并扼杀系统。相反,请使用gensym。在这样的代码中可能仍然存在GC错误,但这不是一个。

最新更新