Home > Software design >  sys.refcount() returning much greater value then expected python3
sys.refcount() returning much greater value then expected python3

Time:10-27

I am learning about GIL in python and tried to run sys.refcount() and recevied value of 148. This might be a very simple question , any help would be appreciated.

Why is the value 148 and not 2 ?

import sys

c = 1
print(sys.getrefcount(c))

>>> 148

CodePudding user response:

int is special.

Its values are very numerous (pun intended) and small, which is the worst-case as far object overhead (it wastes time to allocate, GCs become smaller because they have more heap objects to scan, and wastes time to reference count and deallocate). Typically language runtimes go to pretty great lengths to try to optimizations special cases like int, bool, etc.

Depending on the particular implementation of Python, it's possible that int objects are represented as:

  1. Regular, run-of-the-mill heap-allocated objects (i.e., no special optimizations).
  2. As regular heap-allocated objects, but with a pool of shared objects used to represent all the most common values. (e.g. every instance of 1 is the same object, referenced everywhere where a 1 is used)
  3. Or as a tagged pointer, which involves no heap-allocation at all (for suitably small integer values).

In case 2 or 3, its reference count will not be what you might expect, had it been a "normal" object.

CodePudding user response:

Your Python code isn't the only thing running. Much of the Python standard library is written in Python, and depending on which shell you use that can cause quite a few modules to be imported before the first thing you type. Here under CPython 3.10.0's IDLE:

>>> import sys
>>> len(sys.modules)
159

So just getting to the prompt imported 159(!) modules "under the covers".

"Small" integer objects are shared, across uses, by the CPython implementation. So every instance of 3 across all those modules adds to 3's refcount. Here are some others:

>>> for i in range(-10, 11):
...     print(i, sys.getrefcount(i))
-10 3
-9 3
-8 3
-7 3
-6 3
-5 9
-4 5
-3 12
-2 25
-1 190
0 914
1 804
2 363
3 144
4 202
5 83
6 83
7 38
8 128
9 54
10 64

So 3 is "pretty popular", but 0 is the easy winner. Nothing else is using, e.g., -10 or -9, though.

But do note that knowing this is of no actual value to you. Whether and when Python shares immutable objects is implementation-defined, and can (and does!) change across releases.

  • Related