Memory management 公共lisp中对象的内存使用情况

Memory management 公共lisp中对象的内存使用情况,memory-management,common-lisp,clos,Memory Management,Common Lisp,Clos,有没有办法确定一个类或基本数据类型的实例通常使用了多少内存 我在cl中有一个玩具webframework,它创建和管理web页面,其中包含表示html标记及其属性的类的实例,当它们应该创建html页面时,它们在一个名为children的槽中有子对象。所以我在想,如果采用这种方法,一个用户的会话将花费服务器多少成本。谢谢。据我所知,标准中的任意对象没有类似的解决方案,但有一些依赖于实现的解决方案,如ccl中的ccl:object direct size: CL-USER> (object-d

有没有办法确定一个类或基本数据类型的实例通常使用了多少内存


我在cl中有一个玩具webframework,它创建和管理web页面,其中包含表示html标记及其属性的类的实例,当它们应该创建html页面时,它们在一个名为children的槽中有子对象。所以我在想,如果采用这种方法,一个用户的会话将花费服务器多少成本。谢谢。

据我所知,标准中的任意对象没有类似的解决方案,但有一些依赖于实现的解决方案,如ccl中的
ccl:object direct size

CL-USER> (object-direct-size "foo")
16
但是,请注意,这些函数是否满足您的要求取决于“大小”的含义,因为这些函数通常不包括对象引用的组件的大小。您还可以在前后运行GC、初始化一些对象和

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

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

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

例如:

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
CL-USER>(定义类foo()
((子:访问器子:initarg:child)))
#
CL-USER>(分类栏(foo)
((child2:accessor child2:initarg:child2)))
#
CL-USER>(大小“())
0
CL-USER>(尺寸为“foo”)
16
CL-USER>(大小“(“foo”“bar”))
40
CL-USER>(大小(使实例“foo”)
16
CL-USER>(大小(使实例“foo:child”(“foo”“bar”“baz”))
72
CL-USER>(大小(制作实例)
“酒吧
:儿童“foo”
:child2(生成实例'foo:child(生成数组100)))
456

在公共Lisp中,CLOS对象通常是插槽的集合。通常,这些插槽可能内部存储在某种向量中。CLOS插槽通常包含指向某些数据对象的指针,或者对于一些基本数据类型,可能包含数据本身。这些基本数据类型必须适合内存字:例如fixnums和character。常见的Lisp实现通常不会将更复杂的数据结构内联到插槽中。例如,可以声明一个插槽包含一个fixnums向量。实现不会在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对象本身的大小。那很容易

  • 以某种方式计算一个对象图,其中包含可从该对象访问的对象,确定唯一的内存对象(减去直接分配的基本对象),并将这些对象的所有内存大小相加


我在cl中也有web框架,也在努力解决同样的会话问题,下面是universe发送给我的内容 它似乎在sbcl中起作用

(memory::dump-memory (weblocks::active-sessions))
Total memory used: 99.785706 MB

没错,但是如果没有请求的话,完整的网页是很难创建的,在请求中,hunchentoot为用户创建了许多其他东西。你知道我的意思。我需要一些方法来检查这个动态,但你的答案已经打开了大门谢谢。我想知道是否明智的做法是为html标签和每个标签的实例类。你可能会无缘无故地过度使用“面向对象”的东西。@SebastiánBenítez,也许吧,但我很好地利用了它,这使我能够完全访问页面元素,并定义我自己的标记类型,我可以轻松地将它们插入标记树中。到目前为止,它看起来像一个页面(如果你想知道它的功能,不需要用户通行证)花费了我1.3MB。如果查看页面源代码,您可以看到我在哪里使用了这些构造。当然,这可以通过两种方式实现,持久化页面和单独创建和呈现页面,这些页面将在以后进行gc编辑。当页面过于复杂,无法在没有状态的情况下进行管理时,可以使用PERIS,如上文所述。@danlei我没有使用(时间…)的主要原因是,我认为它将在运行期间报告消耗,但某些内存将在函数完成后被gc删除,对吗?是的。我添加了一个小的(未经测试且未经过深思熟虑的)示例片段-这有帮助吗?我需要阅读几遍才能消化它,感谢您的回答它似乎不适用于最新的sbcl(1.5.3):
Symbol“LAYOUT-N-untaged-slot”在SB-KERNEL包中找不到。
(memory::dump-memory (weblocks::active-sessions))
Total memory used: 99.785706 MB