As others have stated, sys.getsizeof only returns the size of the object structure that represents your data. So if, for instance, you have a dynamic array that you keep adding elements to, sys.getsizeof(my_array) will only ever show the size of the base DynamicArray object, not the growing size of memory that its elements take up.

pympler.asizeof.asizeof() gives an approximate complete size of objects and may be more accurate for you.

from pympler import asizeof
asizeof.asizeof(my_object)  # should give you the full object size
Answer from Engineero on Stack Overflow
🌐
Python
docs.python.org › 3 › library › sys.html
sys — System-specific parameters and functions
If given, default will be returned if the object does not provide means to retrieve the size. Otherwise a TypeError will be raised. getsizeof() calls the object’s __sizeof__ method and adds an additional garbage collector overhead if the object is managed by the garbage collector.
Discussions

BUG: Incorrect results from `sys.getsizeof()` for multi-dimensional arrays
Describe the issue: While sys.getsizeof() seems to work correctly for one-dimensional arrays, it gives, in my opinion, incorrect results for multi-dimensional arrays. import sys import numpy as np ... More on github.com
🌐 github.com
2
January 2, 2022
Strange behavior of sys.getsizeof
Hi! I expected that sys,getsizeof would return the same results in the following two scripts, but it returns different results. Why? Script 1 import sys a = [] a += [0] print(a) print(sys.getsizeof(a)) Output of script1 [0] 72 Script 2 import sys a = [] a.append(0) print(a) print(sys.getsizeof(a)) ... More on discuss.python.org
🌐 discuss.python.org
0
1
April 29, 2025
[Python 3.5] What does sys.getsizeof(object) show me exactly when I use this instruction?
According to the docs, getsizeof is implementation-specific - it calls an object's __sizeof__ method on the object to retrieve this data. It might not be accurate for non-builtins. Edit: Here's an example: from collections import UserList import sys class MyList(UserList): def __sizeof__(self): return 100000000 class MyList2(UserList): pass my_new_list = MyList(range(100)) my_second_list = MyList2(range(100)) my_regular_list = list(range(100)) print("size of my_new_list:", sys.getsizeof(my_new_list)) # 100000024 print("size of my_second_list:", sys.getsizeof(my_second_list)) #56 print("size of my_regular_list:", sys.getsizeof(my_regular_list)) # 1008 Notice there's a bit of overhead that is also calculated. More on reddit.com
🌐 r/learnprogramming
9
1
June 28, 2017
What is the difference between len() and sys.getsizeof() methods in python? - Stack Overflow
They are not the same thing at all. len() queries for the number of items contained in a container. For a string that's the number of characters: Return the length (the number of items) of an object. The argument may be a sequence (string, tuple or list) or a mapping (dictionary). sys.getsizeof() ... More on stackoverflow.com
🌐 stackoverflow.com
🌐
Ned Batchelder
nedbatchelder.com › blog › 202002 › sysgetsizeof_is_not_what_you_want
sys.getsizeof is not what you want | Ned Batchelder
February 9, 2020 - But the fact is, sys.getsizeof is almost never what you want, for two reasons: it doesn’t count all the bytes, and it counts the wrong bytes. ... Only the memory consumption directly attributed to the object is accounted for, not the memory consumption of objects it refers to.
🌐
GitHub
github.com › numpy › numpy › issues › 20707
BUG: Incorrect results from `sys.getsizeof()` for multi-dimensional arrays · Issue #20707 · numpy/numpy
January 2, 2022 - import sys import numpy as np a = np.arange(10).reshape(2, 5) print('Array:') print(a) print('Bytes as reported by NumPy:', a.nbytes) print('Size as Python sees it:', sys.getsizeof(a)) print('The number of bytes is the same for the one-dimensional version:', a.flatten().nbytes) print('But `sys.getsizeof()` gives a different result:', sys.getsizeof(a.flatten())) print('Just to make sure it is not the "fault" of `flatten()`:', sys.getsizeof(np.arange(10))) print('There seems to be consistent 104 byte overhead of `sys.getsizeof():') for size in [10, 100, 1_000, 10_000]: arr = np.arange(size) diff
Author   pya
🌐
Python.org
discuss.python.org › python help
Strange behavior of sys.getsizeof - Python Help - Discussions on Python.org
April 29, 2025 - Hi! I expected that sys,getsizeof would return the same results in the following two scripts, but it returns different results. Why? Script 1 import sys a = [] a += [0] print(a) print(sys.getsizeof(a)) Output of script1 [0] 72 Script 2 import sys a = [] a.append(0) print(a) print(sys.getsizeof(a)) ...
🌐
Reddit
reddit.com › r/learnprogramming › [python 3.5] what does sys.getsizeof(object) show me exactly when i use this instruction?
r/learnprogramming on Reddit: [Python 3.5] What does sys.getsizeof(object) show me exactly when I use this instruction?
June 28, 2017 -

I was watching a numpy video on YouTube and the presenter made a point about numpy arrays versus python lists, and he did so in an odd manner. He was pointing out that one of the advantages of numpy array are how they take up less space, but when I tried to remake his demonstration in IDLE I didn’t get the same results.

import numpy as np
import sys

a = range(1000)
print('Information pertaining to a')
print('Get size', sys.getsizeof(a))
print('Type', type(a))
print('Print of actual a', a, '\n')

b = []
for i in range (1000):
    b.append(i)
print('Information pertaining to b')
print('Get size', sys.getsizeof(b))
print('Type', type(b))
print('Print of actual b', b, '\n')

c = np.arange(1000)
print('Information pertaining to c')
print('Get size', sys.getsizeof(c))
print('Type', type(c))
print('Print of actual c', c, '\n')

d = 5
print('Information pertaining to d')
print('Get size', sys.getsizeof(d))
print('Type', type(d))
print('Print of actual d', d, '\n')

e = 'e'
print('Information pertaining to e')
print('Get size', sys.getsizeof(e))
print('Type', type(e))
print('Print of actual e', e, '\n')

When I run this code, it shows me that the np array is indeed a bit lighter than the py list (9000 bytes vs 8000 bytes), but for some reason it doesn’t show me the full size of the range. It looks like he’s only showing me the space taken up by the letter 'a' (only 48 bytes). So I’m wondering, what exactly is getsizeof() meant to do? And why does it treat different kinds of list-like objects differently?

Top answer
1 of 2
85

They are not the same thing at all.

len() queries for the number of items contained in a container. For a string that's the number of characters:

Return the length (the number of items) of an object. The argument may be a sequence (string, tuple or list) or a mapping (dictionary).

sys.getsizeof() on the other hand returns the memory size of the object:

Return the size of an object in bytes. The object can be any type of object. All built-in objects will return correct results, but this does not have to hold true for third-party extensions as it is implementation specific.

Python string objects are not simple sequences of characters, 1 byte per character.

Specifically, the sys.getsizeof() function includes the garbage collector overhead if any:

getsizeof() calls the object’s __sizeof__ method and adds an additional garbage collector overhead if the object is managed by the garbage collector.

String objects do not need to be tracked (they cannot create circular references), but string objects do need more memory than just the bytes per character. In Python 2, __sizeof__ method returns (in C code):

Py_ssize_t res;
res = PyStringObject_SIZE + PyString_GET_SIZE(v) * Py_TYPE(v)->tp_itemsize;
return PyInt_FromSsize_t(res);

where PyStringObject_SIZE is the C struct header size for the type, PyString_GET_SIZE basically is the same as len() and Py_TYPE(v)->tp_itemsize is the per-character size. In Python 2.7, for byte strings, the size per character is 1, but it's PyStringObject_SIZE that is confusing you; on my Mac that size is 37 bytes:

>>> sys.getsizeof('')
37

For unicode strings the per-character size goes up to 2 or 4 (depending on compilation options). On Python 3.3 and newer, Unicode strings take up between 1 and 4 bytes per character, depending on the contents of the string.

For containers such as dictionaries or lists that reference other objects, the memory size given covers only the memory used by the container and the pointer values used to reference those other objects. There is no straightforward method of including the memory size of the ‘contained’ objects because those same objects could have many more references elsewhere and are not necessarily owned by a single container.

The documentation states it like this:

Only the memory consumption directly attributed to the object is accounted for, not the memory consumption of objects it refers to.

If you need to calculate the memory footprint of a container and anything referenced by that container you’ll have to use some method of traversing to those contained objects and get their size; the documentation points to a recursive recipe.

2 of 2
2

key difference is that len() will give actual length of elements in container , Whereas sys.getsizeof() will give it's memory size which it occupy

for more information read docs of python which is available at https://docs.python.org/3/library/sys.html#module-sys

Find elsewhere
🌐
ProgramCreek
programcreek.com › python › example › 13351 › sys.getsizeof
Python Examples of sys.getsizeof
def get_size(self, msg, seen=None): """Recursively finds size of objects""" size = sys.getsizeof(msg) if seen is None: seen = set() obj_id = id(msg) if obj_id in seen: return 0 seen.add(obj_id) if isinstance(msg, dict): size += sum([self.get_size(v, seen) for v in msg.values()]) size += sum([self.get_size(k, seen) for k in msg.keys()]) elif hasattr(msg, '__dict__'): size += self.get_size(msg.__dict__, seen) elif hasattr(msg, '__iter__') and not isinstance(msg, (str, bytes, bytearray)): size += sum([self.get_size(i, seen) for i in msg]) return size
Top answer
1 of 2
3

From the documentation (my bold) (a):

Only the memory consumption directly attributed to the object is accounted for, not the memory consumption of objects it refers to.

So the size of v does not include the sizes of the elements it refers to.

If you change kite into kites, you'll also see that its size increases but not the size of v (I've replaced your big number with 100...00 in the output to ease formatting):

1 size is: 12
2 size is: 12
kite size is: 25
100...00 size is: 102
Total size is: 48

1 size is: 12
2 size is: 12
kites size is: 26
100...00 size is: 102
Total size is: 48

Think of it like this:

       /  +-----+
      | v | ref | -> 1
Size  |   | ref | -> 2
 of v |   | ref | -> 'kite'
      |   | ref | -> 100**100
       \  +-----+
                     \___________________________/
                      Size of things referred
                       to by v

(a) That page also has a link to a recipe for doing recursive size calculations if you need that information. The link is duplicated here for citation, and the code is duplicated below to make this answer more self-contained.

Plugging your structure into that code gives:

48 <type 'list'> [1, 2, 'kites', 100...00L]
12 <type 'int'> 1
12 <type 'int'> 2
26 <type 'str'> 'kites'
102 <type 'long'> 100...00L
200

The code, with your structure, is shown below.

from __future__ import print_function
from sys import getsizeof, stderr
from itertools import chain
from collections import deque
try:
    from reprlib import repr
except ImportError:
    pass

def total_size(o, handlers={}, verbose=False):
    """ Returns the approximate memory footprint an object and all of its contents.

    Automatically finds the contents of the following builtin containers and
    their subclasses:  tuple, list, deque, dict, set and frozenset.
    To search other containers, add handlers to iterate over their contents:

        handlers = {SomeContainerClass: iter,
                    OtherContainerClass: OtherContainerClass.get_elements}

    """
    dict_handler = lambda d: chain.from_iterable(d.items())
    all_handlers = {tuple: iter,
                    list: iter,
                    deque: iter,
                    dict: dict_handler,
                    set: iter,
                    frozenset: iter,
                   }
    all_handlers.update(handlers)     # user handlers take precedence
    seen = set()                      # track which object id's have already been seen
    default_size = getsizeof(0)       # estimate sizeof object without __sizeof__

    def sizeof(o):
        if id(o) in seen:       # do not double count the same object
            return 0
        seen.add(id(o))
        s = getsizeof(o, default_size)

        if verbose:
            print(s, type(o), repr(o), file=stderr)

        for typ, handler in all_handlers.items():
            if isinstance(o, typ):
                s += sum(map(sizeof, handler(o)))
                break
        return s

    return sizeof(o)


##### Example call #####

if __name__ == '__main__':
    v = [1,2,'kites',100**100]
    print(total_size(v, verbose=True))
2 of 2
1

This happens because your "Total size" is actually the size of the list structure without the contents. So you can store an object of any size there and it won't change your "Total size." You need a "recursive" getsizeof(), and for that, see here: Python deep getsizeof list with contents? or here: Deep version of sys.getsizeof

🌐
Python
bugs.python.org › issue12414
Issue 12414: getsizeof() on code objects is wrong - Python tracker
June 26, 2011 - This issue tracker has been migrated to GitHub, and is currently read-only. For more information, see the GitHub FAQs in the Python's Developer Guide · This issue has been migrated to GitHub: https://github.com/python/cpython/issues/56623
🌐
Reddit
reddit.com › r/learnpython › size of python objects different? [real memory vs sys.getsizeof()]
r/learnpython on Reddit: Size of python objects different? [Real memory vs sys.getsizeof()]
November 11, 2016 -

Hi Pyople!

Yesterday I learned about sys.getsizeof() function and try some code. More specifically:

lst = [i for i in range(1000000000)]  # one mld numbers, creating for about a minute

When I use sys.getsizeof(lst), it returns: 8058558880. Which is correct. But when I look at my system resources in Linux Centos7 IPython (Python 3.4) I see: ipython Memory: 39592564 K Shared Mem: 5176 K - That's freaking 40GB.

I don't understand why, if a object is 8 GB in size, takes 40 KGB system memory. I tried it in list that had around 400 MB and system took 400 * 5 (approx) = 2 GB (approx)

Why is it taking 5-times more memory than it should? Or is the problem only because I tried it in iPython / Konsole? And in program it wouldn't be a problem?

🌐
GitHub
github.com › python › cpython › issues › 128762
`sys.getsizeof()` does not include inline values · Issue #128762 · python/cpython
January 12, 2025 - Bug report Bug description: Commit tested: 5e65a1a I have a program that allocates numerous instances of this type: @dataclass class Node: cdr: Self | None BIG_DATA = None for i in range(50): BIG_DATA = Node(BIG_DATA) print(sys.getsizeof...
Author   hashbrowncipher
🌐
TutorialsPoint
tutorialspoint.com › difference-between-sizeof-and-getsizeof-method-in-python
Difference between __sizeof__() and getsizeof() method in Python
April 17, 2023 - The getsizeof() operator internally calls the __sizeof__() operator and adds an extra overhead while returning the size of the object for garbage collection. It returns 64 bytes(depending upon the system it can vary) for an empty list and 8 bytes for each list element.
🌐
Python.org
discuss.python.org › python help
Strange behavior of sys.getsizeof - #6 by Stefan2 - Python Help - Discussions on Python.org
April 29, 2025 - Hi! I expected that sys,getsizeof would return the same results in the following two scripts, but it returns different results. Why? Script 1 import sys a = [] a += [0] print(a) print(sys.getsizeof(a)) Output of scrip…
🌐
GeeksforGeeks
geeksforgeeks.org › python › difference-between-__sizeof__-and-getsizeof-method-python
Difference between __sizeof__() and getsizeof() method - Python - GeeksforGeeks
July 12, 2025 - We have two Python methods, __sizeof__() and sys.getsizeof(), both used to measure the memory size of an object. While they seem similar, they produce different results. For example, calling these methods on the same object may return different values. Understanding this difference is essential for efficient memory management especially in large-scale applications. Let's explore how these methods work ...
Top answer
1 of 1
4

If you check the size of a list, it will be provide the size of the list data structure, including the pointers to its constituent elements. It won't consider the size of elements.

str1_size = sys.getsizeof(['a' for i in xrange(0, 1024)])
str2_size = sys.getsizeof(['abc' for i in xrange(0, 1024)])
int_size = sys.getsizeof([123 for i in xrange(0, 1024)])
none_size = sys.getsizeof([None for i in xrange(0, 1024)])
str1_size == str2_size == int_size == none_size

The size of empty list: sys.getsizeof([]) == 72
Add an element: sys.getsizeof([1]) == 80
Add another element: sys.getsizeof([1, 1]) == 88
So each element adds 4 bytes.
To get 1024 bytes, we need (1024 - 72) / 8 = 119 elements.

The size of the list with 119 elements: sys.getsizeof([None for i in xrange(0, 119)]) == 1080.
This is because a list maintains an extra buffer for inserting more items, so that it doesn't have to resize every time. (The size comes out to be same as 1080 for number of elements between 107 and 126).

So what we need is an immutable data structure, which doesn't need to keep this buffer - tuple.

empty_tuple_size = sys.getsizeof(())                     # 56
single_element_size = sys.getsizeof((1,))                # 64
pointer_size = single_element_size - empty_tuple_size    # 8
n_1mb = (1024 - empty_tuple_size) / pointer_size         # (1024 - 56) / 8 = 121
tuple_1mb = (1,) * n_1mb
sys.getsizeof(tuple_1mb) == 1024

So this is your answer to get a 1MB data structure: (1,)*121

But note that this is only the size of tuple and the constituent pointers. For the total size, you actually need to add up the size of individual elements.


Alternate:

sys.getsizeof('') == 37
sys.getsizeof('1') == 38     # each character adds 1 byte

For 1 MB, we need 987 characters:

sys.getsizeof('1'*987) == 1024

And this is the actual size, not just the size of pointers.

🌐
Dataquest Community
community.dataquest.io › q&a › dq courses
Ndarray.nbytes vs sys.getsizeof(ndarray) - DQ Courses - Dataquest Community
November 16, 2020 - Hello all! I’m working on a NumPy module. Here’s a snippet of code for some insight: from sys import getsizeof as sz values = [-127, -57, -6, 0, 9, 42, 125] x = np.array(values, dtype=np.int8) y = np.array(values) print("x -> ", x.nbytes, sz(x)) print("y -> ", y.nbytes, sz(y)) Output: x -> 7 103 y -> 56 152 NumPy manual indicates, ndarray.nbytes Does not include memory consumed by non-element attributes of the array object.
🌐
GitHub
github.com › python › cpython › issues › 103131
`sys.getsizeof` and `sys.set_asyncgen_hooks` are not converted to AC · Issue #103131 · python/cpython
March 30, 2023 - I found this while working on python/typeshed#9987 I've noticed that most of the functions inside sys do have __text_signature__. While sys.getsizeof doesn't. >>> import sys >>> sys.addaudithook.__text_signature__ '($module, /, hook)' >>...
Author   sobolevn
Top answer
1 of 2
7

You misunderstand what sys.getsizeof() does. It returns the amount of memory Python uses for a string object, not length of the line.

Python string objects track reference counts, the object type and other metadata together with the actual characters, so 2978 bytes is not the same thing as the string length.

See the stringobject.h definition of the type:

typedef struct {
    PyObject_VAR_HEAD
    long ob_shash;
    int ob_sstate;
    char ob_sval[1];

    /* Invariants:
     *     ob_sval contains space for 'ob_size+1' elements.
     *     ob_sval[ob_size] == 0.
     *     ob_shash is the hash of the string or -1 if not computed yet.
     *     ob_sstate != 0 iff the string object is in stringobject.c's
     *       'interned' dictionary; in this case the two references
     *       from 'interned' to this object are *not counted* in ob_refcnt.
     */
} PyStringObject;

where PyObject_VAR_HEAD is defined in object.h, where the standard ob_refcnt, ob_type and ob_size fields are all defined.

So a string of length 2957 takes 2958 bytes (string length + null) and the remaining 20 bytes you see are to hold the reference count, the type pointer, the object 'size' (string length here), the cached string hash and the interned state flag.

Other object types will have different memory footprints, and the exact sizes of the C types used differ from platform to platform as well.

2 of 2
3

A string object representing 2957 bytes of data takes more than 2957 bytes of memory to represent, due to overhead such as the type pointer and the reference count. sys.getsizeof includes this additional overhead.