8

有没有办法找出一个类或基本数据类型的实例使用了多少内存?

我在 cl 中有一个玩具网络框架,它使用代表 html 标签及其属性的类实例创建和管理网页,并且由于它们应该创建一个 html 页面,因此它们在一个名为 children 的插槽中有子节点。所以我在想如果我采用这种方法,用户的会话将花费多少服务器。谢谢。

4

3 回答 3

7

据我所知,标准中的任意对象都没有这样的东西,但是有依赖于实现的解决方案,比如ccl:object-direct-size在 CCL 中:

CL-USER> (object-direct-size "foo")
16

但是,请注意,这些是否符合您的要求取决于您所说的“大小”,因为这些函数通常不包括对象引用的组件的大小。您还可以运行 GC,初始化一些对象并比较 前后room输出。

另外,请注意time通常包括分配信息:

CL-USER> (time (length (make-array 100000)))
(LENGTH (MAKE-ARRAY 100000))
took 0 milliseconds (0.000 seconds) to run.
During that period, and with 2 available CPU cores,
     0 milliseconds (0.000 seconds) were spent in user mode
     0 milliseconds (0.000 seconds) were spent in system mode
 400,040 bytes of memory allocated.
100000

也许您可以尝试这样的事情(未经测试,实际上只是一个快速破解):

(defmethod size ((object standard-object))
  (let ((size (ccl:object-direct-size object)))
    (dolist (slot (mapcar #'ccl:slot-definition-name
                          (ccl:class-slots (class-of object))))
      (when (slot-boundp object slot)
        (incf size (size (slot-value object slot)))))
    size))

(defmethod size ((list list))
  (reduce (lambda (acc object) (+ acc (size object)))
          list
          :initial-value (ccl:object-direct-size list)))

(defmethod size (object)
  (ccl:object-direct-size object))

例如:

CL-USER> (defclass foo ()
           ((child :accessor child :initarg :child)))
#<STANDARD-CLASS FOO>
CL-USER> (defclass bar (foo)
           ((child2 :accessor child2 :initarg :child2)))
#<STANDARD-CLASS BAR>
CL-USER> (size '())
0
CL-USER> (size "foo")
16
CL-USER> (size '("foo" "bar"))
40
CL-USER> (size (make-instance 'foo))
16
CL-USER> (size (make-instance 'foo :child '("foo" "bar" "baz")))
72
CL-USER> (size (make-instance
                'bar
                :child "foo"
                :child2 (make-instance 'foo :child (make-array 100))))
456
于 2012-09-01T20:27:04.673 回答
6

在 Common Lisp 中,CLOS 对象通常是插槽的集合。通常,这些插槽可能会在内部存储在某种向量中。CLOS 槽通常包含指向某个数据对象的指针,或者对于一些原始数据类型,可能包含数据本身。这些原始数据类型必须适合一个内存字:例如 fixnums 和 characters。Common Lisp 实现通常不会将更复杂的数据结构内联到插槽中。例如,可以声明一个插槽以包含一个固定数字向量。实现不会在 CLOS 对象内分配这个向量。CLOS 对象将指向一个矢量对象。

那么 CLOS 对象本身应该占用:槽数 * 字长 + 开销。

假设一个字长 4 个字节,32 位。

这可能是具有十个插槽的 CLOS 对象的大小:

10 slots * 4 bytes + 8 bytes = 48 bytes

现在想象一下,CLOS 对象的每个槽都指向一个不同的字符串,每个字符串的长度为 100 字节。

上面的例子:

1 CLOS object + 10 strings each 100 bytes.

48 bytes + 10 * 100 = 1048 bytes

现在想象每个插槽都指向同一个字符串:

1 CLOS object + 1 string of 100 bytes.

48 bytes + 100 bytes = 148 bytes

要计算 CLOS 对象的大小,您可以:

  • 只需计算 CLOS 对象本身的大小。这很容易。

  • 以某种方式计算可以从对象访问的对象图,确定唯一的内存对象(减去直接分配的原始对象)并将这些对象的所有内存大小相加。

于 2012-09-02T09:34:17.407 回答
2

我在 cl 中也有 Web 框架,也在为相同的会话问题而苦苦挣扎,这是宇宙发送给我的内容https://people.gnome.org/~xan/memory.lisp 它似乎在 sbcl 中工作

(memory::dump-memory (weblocks::active-sessions))
Total memory used: 99.785706 MB
于 2014-12-07T03:28:08.783 回答