哈希表的疑似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。然后,辅助函数输出两个修改后的哈希表,它们保存在new-hash1和 中new-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 错误,但这不是一个。


以上是哈希表的疑似SBCL垃圾收集错误的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>