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
("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
.