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
.