Documentation: Analyzing memory usage

CMUCL includes a number of tools that allow a user to determine how many objects of a given type have been allocated in a given image, and why certain objects are not being reclaimed by the garbage collector. These functions are called VM::LIST-ALLOCATED-OBJECTS and VM::LIST-REFERENCING-OBJECTS. Each takes a first SPACE argument indicating whether to scan dynamic space, static space or read-only space.

The example below shows how to obtain a list all objects of type double-float in read-only space, and a list of all strings of length 42 in read-only space:

USER> (vm::list-allocated-objects :read-only :type vm::double-float-type)
(0.0d0 1.8446744073709553d+19 -1.8446744073709553d+19 -3.141592653589793d0
 1.5707963267948966d0 -1.5707963267948966d0 3.141592653589793d0 -1.0d0 1.0d0
 -0.0d0 0.0d0 0.0d0 -0.0d0 0.0d0 0.0d0 1.0d0 177.61896501848597d0
 2.147483648d+9 -2.1474836490000002d+9 1.1102230246251568d-16
 5.551115123125784d-17 -2.2250738585072014d-308 -2.2250738585072014d-308
 4.940656458412465d-324 -1.7976931348623157d+308 1.7976931348623157d+308
 -4.940656458412465d-324 1.1102230246251568d-16 5.551115123125784d-17
 -1.7976931348623157d+308 4.940656458412465d-324 -4.940656458412465d-324
 1.7976931348623157d+308 2.2250738585072014d-308 2.2250738585072014d-308
 5.368709110000001d+8 0.0d0 -5.36870912d+8 0.0d0 0.0d0 -0.0d0
 #.EXT:DOUBLE-FLOAT-NEGATIVE-INFINITY #.EXT:DOUBLE-FLOAT-NEGATIVE-INFINITY
 #.EXT:DOUBLE-FLOAT-POSITIVE-INFINITY 308.2547155599167d0 -307.6526555685887d0
 1.0d+7 0.001d0 1.0d+16 0.1d0 1.0d0 -3.141592653589793d0 0.5d0 0.25d0 4.0d0
 2.983336292480083d-154 1.5707963267948966d0 -1.5707963267948966d0
 3.351951982485649d+153 3.0d0 1.2d0 0.7071067811865475d0 0.6931471805599453d0
 3.141592653589793d0 10.0d0 0.3010299914836512d0 0.0d0 0.0d0 0.5d0
 #.EXT:DOUBLE-FLOAT-POSITIVE-INFINITY 2.0d0 4.450147717014402d-308 -1.0d0 0.0d0
 1.0d0 #.EXT:DOUBLE-FLOAT-POSITIVE-INFINITY -1.0d0 0.0d0 1.0d0
 5.368709110000001d+8 -5.36870912d+8)
USER> (vm::list-allocated-objects :read-only :type vm::simple-string-type
                                  :test (lambda (obj) (= 42 (length obj))))
("DEFMETHOD WRAPPER-FETCHER (STANDARD-CLASS)"
 "(.pv-cell. .next-method-call. specializer)"
 "DEFUN GET-COMPLEX-INITIALIZATION-FUNCTIONS"
 "DEFMETHOD DOCUMENTATION (FUNCTION (EQL #))"
 [...]
 "Veritas aeterna, can't declare ~S special."
 "Can't declare ~S special, it is a keyword."
 "Trying to declare ~S special, which is ~A."
 "COMPILED-DEBUG-FUNCTION-COMPILER-DEBUG-FUN"
 "Too large to be represented as a ~S:~%  ~S"
 "~D is too big; ~S only has ~D dimension~:P")

and the example below shows how to find all references to a given object in a given space:

USER> (vm::list-referencing-objects :static *print-case*)
(common-lisp::*previous-case* *print-case* #<(simple-vector 4096) {28018817}>
 :downcase #<(simple-vector 2729) {28002767}>)
USER> (vm::list-referencing-objects :static #\Nul)
((#\Null 8 sparc:simple-string-type) ("Nul" . #\Null) ("^@" . #\Null)
 ("Null" . #\Null))

These functions can produce lots of output; you probably don't want to have *PRINT-ARRAY* set. More information on the breakdown of types of objets allocated and the space that they occupy is available by calling (ROOM T).

If you have more specific needs, CMUCL includes a function VM::MAP-ALLOCATED-OBJECTS that allows you to walk the heap; it calls a user-provided function on each allocated object, with arguments of the object, its size and its type. Examples of usage are available in the CMUCL source code, in the file src/code/room.lisp.

by Eric Marsden