4

Note that the following original test is errorneous and has been superseded by the EDITED version below.

(progn
  (message "Before: %S" (memory-use-counts))
  (let ((x (make-list 100000000 0)))
    (message "Use: %S" (memory-use-counts)))
  (message "Garbage Collect: %S" (garbage-collect))
  (message "After: %S" (memory-use-counts)))

The message output after running the progn form is:

Before: (1974893 657 3944364 16613 2025974 923 92307)
Use: (101974903 658 3944364 16613 2026125 923 92310)
Garbage Collect: ((conses 16 100008801 10478) (symbols 48 2200 4) (strings 32 2545 1051) (string-bytes 1 82237) (vectors 16 3935) (vector-slots 8 69235 13732) (floats 8 11 12) (intervals 56 57 163) (buffers 992 7))
After: (101975693 659 3944734 16613 2029800 923 92506)

One clearly recognizes the huge list of 100000000 conses in the cons counter of the memory-use-counts.

Obviously the garbage-collect after the let-form does not free the memory for the conses of the huge list. Why?

emacs-version:
GNU Emacs 27.0.50 (build 2, x86_64-pc-linux-gnu, GTK+ Version 3.22.30) of 2019-08-16
and
GNU Emacs 26.2 (build 2, x86_64-pc-linux-gnu, GTK+ Version 3.22.30) of 2019-04-12


EDIT:

User legoscia was so kind notify me about an error in my test with his answer.

Nevertheless, we can correct the test (with some self-check at the end) and the result of the new test still acknowledges that the memory for the huge list is not freed:

(progn
  (message "Before: %S" (garbage-collect))
  (let ((x (make-list 100000000 0)))
    (message "Use: %S" (garbage-collect)))
  (message "After: %S" (garbage-collect))
  (message "Let's check again: %S" (garbage-collect)))

The output of this test is:

Before: ((conses 16 8012 7551) (symbols 48 2200 4) (strings 32 2533 939) (string-bytes 1 82159) (vectors 16 3912) (vector-slots 8 68701 11716) (floats 8 10 8) (intervals 56 26 21) (buffers 992 7))
Use: ((conses 16 100008064 733) (symbols 48 2200 4) (strings 32 2558 914) (string-bytes 1 83293) (vectors 16 3913) (vector-slots 8 68847 11570) (floats 8 10 8) (intervals 56 26 21) (buffers 992 7))
After: ((conses 16 100008106 691) (symbols 48 2200 4) (strings 32 2559 913) (string-bytes 1 83491) (vectors 16 3913) (vector-slots 8 68847 11570) (floats 8 10 8) (intervals 56 26 21) (buffers 992 7))
Let’s check again: ((conses 16 100008062 735) (symbols 48 2200 4) (strings 32 2559 913) (string-bytes 1 83495) (vectors 16 3913) (vector-slots 8 68847 11570) (floats 8 10 8) (intervals 56 26 21) (buffers 992 7))

The doc string of garbage-collect says that the (nth 2 (assq 'conses (garbage-collect)))) is the number of conses found live in memory. So, this time the test should be valid.

Relevant part of the doc string of garbage-collect:

Reclaim storage for Lisp objects no longer needed. Garbage collection happens automatically if you cons more than gc-cons-threshold bytes of Lisp data since previous garbage collection. garbage-collect normally returns a list with info on amount of space in use, where each entry has the form (NAME SIZE USED FREE), where:
- NAME is a symbol describing the kind of objects this entry represents,
- SIZE is the number of bytes used by each one,
- USED is the number of those objects that were found live in the heap,
- FREE is the number of those objects that are not live but that Emacs
keeps around for future allocations (maybe because it does not know how
to return them to the OS).

  • Good question. Does it change anything if you move the last two message calls (including the explicit gc) outside the progn? – Drew Sep 17 at 15:09
  • @Drew I played around with several garbage-collect calls afterwards -- and I just tested again. It seems like the memory usage is permanent. Though I didn't wait a long time to check the action of the timers of the garbage collector. – Tobias Sep 17 at 15:14
  • 1
    @Drew The motive for this question is your answer about cyclic lists. A common problem of cyclic lists in other programming languages is that they are not garbage collected since there is no unreferenced head. I wanted to test whether Elisp also has that problem. In this question there is the reference-test that should acknowledge that acyclic lists are always garbage collected. But even this test fails:-(. – Tobias Sep 17 at 15:23
  • Unless you get an answer here or you otherwise discover that it gets gc'd, please consider filing a bug (enhancement request) about it. Even if it's decided that it's not reasonable or feasible for gc to recuperate such conses, perhaps the fact that it doesn't do so should be documented in the Elisp manual. – Drew Sep 17 at 16:55
3

From the docstring of memory-use-counts, emphasis mine:

Return a list of counters that measure how much consing there has been.
Each of these counters increments for a certain kind of object.
The counters wrap around from the largest positive integer to zero.
Garbage collection does not decrease them.

So this is the expected output. I couldn't find any function that tells you how many cons cells are currently in use.

  • Thank you for this rectification! One can use garbage-collect itself to find the number of live conses. I used this to correct my test. Pitingly, the test result is still the same. – Tobias Sep 18 at 9:35
  • I kept the old test in my question to keep your answer valid. Your answer at least shows partially what was going on with the old version of the test. – Tobias Sep 18 at 9:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.