<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="/assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Jason Madden (Posts about cpython)</title><link>https://seecoresoftware.com/</link><description></description><atom:link href="https://seecoresoftware.com/blog/categories/cpython.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><copyright>Contents © 2021 &lt;a href="mailto:jason@seecoresoftware.com"&gt;Jason Madden&lt;/a&gt; </copyright><lastBuildDate>Sat, 04 Dec 2021 18:43:35 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>CPython vs PyPy Memory Usage</title><link>https://seecoresoftware.com/blog/2018/08/cpython-vs-pypy-memory-usage.html</link><dc:creator>Jason Madden</dc:creator><description>&lt;figure&gt;&lt;img src="https://seecoresoftware.com/blog/2018/08/oil-1183699_1920.jpg"&gt;&lt;/figure&gt; &lt;div&gt;&lt;p&gt;If you have lots of "small" objects in a Python program (objects which
have few instance attributes), you may find that the object overhead
starts to become considerable. The common wisdom says that to reduce this in
&lt;a class="reference external" href="https://github.com/python/cpython"&gt;CPython&lt;/a&gt; you need to re-define the classes to use &lt;tt class="docutils literal"&gt;__slots__&lt;/tt&gt;, eliminating
the attribute dictionary. But this comes with the downsides of
limiting flexibility and eliminating the use of class defaults. Would
it surprise you to learn that &lt;a class="reference external" href="http://pypy.org"&gt;PyPy&lt;/a&gt; can significantly, and without
any effort by the programmer, reduce that overhead automatically?&lt;/p&gt;
&lt;p&gt;Let's take a look.&lt;/p&gt;
&lt;!-- TEASER_END --&gt;
&lt;div class="contents topic" id="contents"&gt;
&lt;p class="topic-title first"&gt;Contents&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference internal" href="https://seecoresoftware.com/blog/2018/08/cpython-vs-pypy-memory-usage.html#what-is-being-measured" id="id9"&gt;What Is Being Measured&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="reference internal" href="https://seecoresoftware.com/blog/2018/08/cpython-vs-pypy-memory-usage.html#what-is-not-being-measured" id="id10"&gt;What Is Not Being Measured&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="https://seecoresoftware.com/blog/2018/08/cpython-vs-pypy-memory-usage.html#object-internals" id="id11"&gt;Object Internals&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="reference internal" href="https://seecoresoftware.com/blog/2018/08/cpython-vs-pypy-memory-usage.html#objects-with-dictionaries" id="id12"&gt;Objects with Dictionaries&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="https://seecoresoftware.com/blog/2018/08/cpython-vs-pypy-memory-usage.html#objects-with-slots" id="id13"&gt;Objects With Slots&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="reference internal" href="https://seecoresoftware.com/blog/2018/08/cpython-vs-pypy-memory-usage.html#variable-storage" id="id14"&gt;Variable Storage&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="https://seecoresoftware.com/blog/2018/08/cpython-vs-pypy-memory-usage.html#how-pypy-does-better" id="id15"&gt;How PyPy Does Better&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;Contrary to advice, instead of &lt;a class="reference external" href="https://www.youtube.com/watch?v=k33ZQ4I4p24"&gt;starting at the very beginning&lt;/a&gt;,
we'll jump right to the end. The following graph shows the peak memory
usage of the example program we'll be talking about in this post
across seven different Python implementations: PyPy2 v6.0, PyPy3 v6.0,
CPython 2.7.15, 3.4.9, 3.5.6, 3.6.6, and 3.7.0 &lt;a class="footnote-reference" href="https://seecoresoftware.com/blog/2018/08/cpython-vs-pypy-memory-usage.html#f1" id="id1"&gt;[1]&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For regular objects ("Point3D"), PyPy needs less than 700MB to create
10,000,000, where CPython 2.7 needs almost 3.5 &lt;em&gt;GB&lt;/em&gt;, and CPython 3.x
needs between 1.5 and 2.1 GB &lt;a class="footnote-reference" href="https://seecoresoftware.com/blog/2018/08/cpython-vs-pypy-memory-usage.html#f6" id="id2"&gt;[6]&lt;/a&gt;. Moving to &lt;tt class="docutils literal"&gt;__slots__&lt;/tt&gt; ("Point3DSlot")
brings the CPython overhead closer to—but still higher than—that of PyPy. In particular, note that the PyPy memory usage is
essentially the same whether or not slots are used.&lt;/p&gt;
&lt;?xml version='1.0' encoding='utf-8'?&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="chart-caea74a2-ed82-40e5-a929-00ff6d0a0307" class="pygal-chart" viewbox="0 0 800 600"&gt;&lt;!--Generated with pygal 2.4.0 (lxml) ©Kozea 2012-2016 on 2021-12-04--&gt;&lt;!--http://pygal.org--&gt;&lt;!--http://github.com/Kozea/pygal--&gt;&lt;defs&gt;&lt;style type="text/css"&gt;#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307{-webkit-user-select:none;-webkit-font-smoothing:antialiased;font-family:Consolas,"Liberation Mono",Menlo,Courier,monospace}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .title{font-family:Consolas,"Liberation Mono",Menlo,Courier,monospace;font-size:16px}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .legends .legend text{font-family:Consolas,"Liberation Mono",Menlo,Courier,monospace;font-size:14px}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .axis text{font-family:Consolas,"Liberation Mono",Menlo,Courier,monospace;font-size:10px}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .axis text.major{font-family:Consolas,"Liberation Mono",Menlo,Courier,monospace;font-size:10px}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .text-overlay text.value{font-family:Consolas,"Liberation Mono",Menlo,Courier,monospace;font-size:16px}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .text-overlay text.label{font-family:Consolas,"Liberation Mono",Menlo,Courier,monospace;font-size:10px}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .tooltip{font-family:Consolas,"Liberation Mono",Menlo,Courier,monospace;font-size:14px}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 text.no_data{font-family:Consolas,"Liberation Mono",Menlo,Courier,monospace;font-size:64px}
#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307{background-color:rgba(249,249,249,1)}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 path,#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 line,#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 rect,#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 circle{-webkit-transition:150ms;-moz-transition:150ms;transition:150ms}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .graph &amp;gt; .background{fill:rgba(249,249,249,1)}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .plot &amp;gt; .background{fill:rgba(255,255,255,1)}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .graph{fill:rgba(0,0,0,.87)}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 text.no_data{fill:rgba(0,0,0,1)}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .title{fill:rgba(0,0,0,1)}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .legends .legend text{fill:rgba(0,0,0,.87)}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .legends .legend:hover text{fill:rgba(0,0,0,1)}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .axis .line{stroke:rgba(0,0,0,1)}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .axis .guide.line{stroke:rgba(0,0,0,.54)}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .axis .major.line{stroke:rgba(0,0,0,.87)}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .axis text.major{fill:rgba(0,0,0,1)}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .axis.y .guides:hover .guide.line,#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .line-graph .axis.x .guides:hover .guide.line,#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .stackedline-graph .axis.x .guides:hover .guide.line,#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .xy-graph .axis.x .guides:hover .guide.line{stroke:rgba(0,0,0,1)}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .axis .guides:hover text{fill:rgba(0,0,0,1)}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .reactive{fill-opacity:.7;stroke-opacity:.8}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .ci{stroke:rgba(0,0,0,.87)}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .reactive.active,#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .active .reactive{fill-opacity:.8;stroke-opacity:.9;stroke-width:4}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .ci .reactive.active{stroke-width:1.5}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .series text{fill:rgba(0,0,0,1)}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .tooltip rect{fill:rgba(255,255,255,1);stroke:rgba(0,0,0,1);-webkit-transition:opacity 150ms;-moz-transition:opacity 150ms;transition:opacity 150ms}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .tooltip .label{fill:rgba(0,0,0,.87)}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .tooltip .label{fill:rgba(0,0,0,.87)}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .tooltip .legend{font-size:.8em;fill:rgba(0,0,0,.54)}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .tooltip .x_label{font-size:.6em;fill:rgba(0,0,0,1)}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .tooltip .xlink{font-size:.5em;text-decoration:underline}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .tooltip .value{font-size:1.5em}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .bound{font-size:.5em}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .max-value{font-size:.75em;fill:rgba(0,0,0,.54)}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .map-element{fill:rgba(255,255,255,1);stroke:rgba(0,0,0,.54) !important}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .map-element .reactive{fill-opacity:inherit;stroke-opacity:inherit}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .color-0,#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .color-0 a:visited{stroke:#F44336;fill:#F44336}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .color-1,#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .color-1 a:visited{stroke:#3F51B5;fill:#3F51B5}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .color-2,#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .color-2 a:visited{stroke:#009688;fill:#009688}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .color-3,#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .color-3 a:visited{stroke:#FFC107;fill:#FFC107}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .color-4,#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .color-4 a:visited{stroke:#FF5722;fill:#FF5722}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .color-5,#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .color-5 a:visited{stroke:#9C27B0;fill:#9C27B0}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .color-6,#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .color-6 a:visited{stroke:#03A9F4;fill:#03A9F4}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .text-overlay .color-0 text{fill:black}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .text-overlay .color-1 text{fill:black}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .text-overlay .color-2 text{fill:black}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .text-overlay .color-3 text{fill:black}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .text-overlay .color-4 text{fill:black}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .text-overlay .color-5 text{fill:black}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .text-overlay .color-6 text{fill:black}
#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 text.no_data{text-anchor:middle}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .guide.line{fill:none}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .centered{text-anchor:middle}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .title{text-anchor:middle}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .legends .legend text{fill-opacity:1}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .axis.x text{text-anchor:middle}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .axis.x:not(.web) text[transform]{text-anchor:start}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .axis.x:not(.web) text[transform].backwards{text-anchor:end}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .axis.y text{text-anchor:end}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .axis.y text[transform].backwards{text-anchor:start}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .axis.y2 text{text-anchor:start}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .axis.y2 text[transform].backwards{text-anchor:end}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .axis .guide.line{stroke-dasharray:4,4}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .axis .major.guide.line{stroke-dasharray:6,6}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .horizontal .axis.y .guide.line,#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .horizontal .axis.y2 .guide.line,#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .vertical .axis.x .guide.line{opacity:0}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .horizontal .axis.always_show .guide.line,#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .vertical .axis.always_show .guide.line{opacity:1 !important}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .axis.y .guides:hover .guide.line,#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .axis.y2 .guides:hover .guide.line,#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .axis.x .guides:hover .guide.line{opacity:1}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .axis .guides:hover text{opacity:1}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .nofill{fill:none}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .subtle-fill{fill-opacity:.2}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .dot{stroke-width:1px;fill-opacity:1}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .dot.active{stroke-width:5px}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .dot.negative{fill:transparent}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 text,#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 tspan{stroke:none !important}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .series text.active{opacity:1}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .tooltip rect{fill-opacity:.95;stroke-width:.5}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .tooltip text{fill-opacity:1}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .showable{visibility:hidden}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .showable.shown{visibility:visible}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .gauge-background{fill:rgba(229,229,229,1);stroke:none}#chart-caea74a2-ed82-40e5-a929-00ff6d0a0307 .bg-lines{stroke:rgba(249,249,249,1);stroke-width:2px}&lt;/style&gt;&lt;script type="text/javascript"&gt;window.pygal = window.pygal || {};window.pygal.config = window.pygal.config || {};window.pygal.config['caea74a2-ed82-40e5-a929-00ff6d0a0307'] = {"allow_interruptions": false, "box_mode": "extremes", "classes": ["pygal-chart"], "css": ["file://style.css", "file://graph.css"], "defs": [], "disable_xml_declaration": false, "dots_size": 2.5, "dynamic_print_values": false, "explicit_size": false, "fill": false, "force_uri_protocol": "https", "formatter": null, "half_pie": false, "height": 600, "include_x_axis": false, "inner_radius": 0, "interpolate": null, "interpolation_parameters": {}, "interpolation_precision": 250, "inverse_y_axis": false, "js": ["//kozea.github.io/pygal.js/2.0.x/pygal-tooltips.min.js"], "legend_at_bottom": false, "legend_at_bottom_columns": null, "legend_box_size": 12, "logarithmic": false, "margin": 20, "margin_bottom": null, "margin_left": null, "margin_right": null, "margin_top": null, "max_scale": 16, "min_scale": 4, "missing_value_fill_truncation": "x", "no_data_text": "No data", "no_prefix": false, "order_min": null, "pretty_print": false, "print_labels": false, "print_values": false, "print_values_position": "center", "print_zeroes": true, "range": null, "rounded_bars": null, "secondary_range": null, "show_dots": true, "show_legend": true, "show_minor_x_labels": true, "show_minor_y_labels": true, "show_only_major_dots": false, "show_x_guides": false, "show_x_labels": true, "show_y_guides": true, "show_y_labels": true, "spacing": 10, "stack_from_top": false, "strict": false, "stroke": true, "stroke_style": null, "style": {"background": "rgba(249, 249, 249, 1)", "ci_colors": [], "colors": ["#F44336", "#3F51B5", "#009688", "#FFC107", "#FF5722", "#9C27B0", "#03A9F4", "#8BC34A", "#FF9800", "#E91E63", "#2196F3", "#4CAF50", "#FFEB3B", "#673AB7", "#00BCD4", "#CDDC39", "#9E9E9E", "#607D8B"], "font_family": "Consolas, \"Liberation Mono\", Menlo, Courier, monospace", "foreground": "rgba(0, 0, 0, .87)", "foreground_strong": "rgba(0, 0, 0, 1)", "foreground_subtle": "rgba(0, 0, 0, .54)", "guide_stroke_dasharray": "4,4", "label_font_family": "Consolas, \"Liberation Mono\", Menlo, Courier, monospace", "label_font_size": 10, "legend_font_family": "Consolas, \"Liberation Mono\", Menlo, Courier, monospace", "legend_font_size": 14, "major_guide_stroke_dasharray": "6,6", "major_label_font_family": "Consolas, \"Liberation Mono\", Menlo, Courier, monospace", "major_label_font_size": 10, "no_data_font_family": "Consolas, \"Liberation Mono\", Menlo, Courier, monospace", "no_data_font_size": 64, "opacity": ".7", "opacity_hover": ".8", "plot_background": "rgba(255, 255, 255, 1)", "stroke_opacity": ".8", "stroke_opacity_hover": ".9", "title_font_family": "Consolas, \"Liberation Mono\", Menlo, Courier, monospace", "title_font_size": 16, "tooltip_font_family": "Consolas, \"Liberation Mono\", Menlo, Courier, monospace", "tooltip_font_size": 14, "transition": "150ms", "value_background": "rgba(229, 229, 229, 1)", "value_colors": [], "value_font_family": "Consolas, \"Liberation Mono\", Menlo, Courier, monospace", "value_font_size": 16, "value_label_font_family": "Consolas, \"Liberation Mono\", Menlo, Courier, monospace", "value_label_font_size": 10}, "title": "Memory Usage (in MB)", "tooltip_border_radius": 0, "tooltip_fancy_mode": true, "truncate_label": null, "truncate_legend": null, "width": 800, "x_label_rotation": 0, "x_labels": ["Point3D", "Point3DSlot", "Point3DSlot Uncached Integers"], "x_labels_major": null, "x_labels_major_count": null, "x_labels_major_every": null, "x_title": null, "xrange": null, "y_label_rotation": 0, "y_labels": null, "y_labels_major": null, "y_labels_major_count": null, "y_labels_major_every": null, "y_title": null, "zero": 0, "legends": ["PyPy2", "PyPy3", "CPython 2.7", "CPython 3.4", "CPython 3.5", "CPython 3.6", "CPython 3.7"]}&lt;/script&gt;&lt;script type="text/javascript" xlink:href="https://kozea.github.io/pygal.js/2.0.x/pygal-tooltips.min.js"&gt;&lt;/script&gt;&lt;/defs&gt;&lt;title&gt;Memory Usage (in MB)&lt;/title&gt;&lt;g class="graph bar-graph vertical"&gt;&lt;rect x="0" y="0" width="800" height="600" class="background"&gt;&lt;/rect&gt;&lt;g transform="translate(168, 46)" class="plot"&gt;&lt;rect x="0" y="0" width="611.6" height="514" class="background"&gt;&lt;/rect&gt;&lt;g class="axis y always_show"&gt;&lt;g class="guides"&gt;&lt;path d="M0.000000 504.115385 h611.600000" class="axis major line"&gt;&lt;/path&gt;&lt;text x="-5" y="507.61538461538464" class="major"&gt;0&lt;/text&gt;&lt;title&gt;0&lt;/title&gt;&lt;/g&gt;&lt;g class="guides"&gt;&lt;path d="M0.000000 446.868025 h611.600000" class="guide line"&gt;&lt;/path&gt;&lt;text x="-5" y="450.36802478788405" class=""&gt;400&lt;/text&gt;&lt;title&gt;400&lt;/title&gt;&lt;/g&gt;&lt;g class="guides"&gt;&lt;path d="M0.000000 389.620665 h611.600000" class="guide line"&gt;&lt;/path&gt;&lt;text x="-5" y="393.12066496038346" class=""&gt;800&lt;/text&gt;&lt;title&gt;800&lt;/title&gt;&lt;/g&gt;&lt;g class="guides"&gt;&lt;path d="M0.000000 332.373305 h611.600000" class="guide line"&gt;&lt;/path&gt;&lt;text x="-5" y="335.87330513288293" class=""&gt;1200&lt;/text&gt;&lt;title&gt;1200&lt;/title&gt;&lt;/g&gt;&lt;g class="guides"&gt;&lt;path d="M0.000000 275.125945 h611.600000" class="guide line"&gt;&lt;/path&gt;&lt;text x="-5" y="278.62594530538234" class=""&gt;1600&lt;/text&gt;&lt;title&gt;1600&lt;/title&gt;&lt;/g&gt;&lt;g class="guides"&gt;&lt;path d="M0.000000 217.878585 h611.600000" class="guide line"&gt;&lt;/path&gt;&lt;text x="-5" y="221.3785854778818" class=""&gt;2000&lt;/text&gt;&lt;title&gt;2000&lt;/title&gt;&lt;/g&gt;&lt;g class="guides"&gt;&lt;path d="M0.000000 160.631226 h611.600000" class="guide line"&gt;&lt;/path&gt;&lt;text x="-5" y="164.13122565038123" class=""&gt;2400&lt;/text&gt;&lt;title&gt;2400&lt;/title&gt;&lt;/g&gt;&lt;g class="guides"&gt;&lt;path d="M0.000000 103.383866 h611.600000" class="guide line"&gt;&lt;/path&gt;&lt;text x="-5" y="106.8838658228807" class=""&gt;2800&lt;/text&gt;&lt;title&gt;2800&lt;/title&gt;&lt;/g&gt;&lt;g class="guides"&gt;&lt;path d="M0.000000 46.136506 h611.600000" class="guide line"&gt;&lt;/path&gt;&lt;text x="-5" y="49.636505995380105" class=""&gt;3200&lt;/text&gt;&lt;title&gt;3200&lt;/title&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class="axis x"&gt;&lt;path d="M0.000000 0.000000 v514.000000" class="line"&gt;&lt;/path&gt;&lt;g class="guides"&gt;&lt;path d="M109.774359 0.000000 v514.000000" class="guide line"&gt;&lt;/path&gt;&lt;text x="109.77435897435896" y="529.0" class=""&gt;Point3D&lt;/text&gt;&lt;/g&gt;&lt;g class="guides"&gt;&lt;path d="M305.800000 0.000000 v514.000000" class="guide line"&gt;&lt;/path&gt;&lt;text x="305.8" y="529.0" class=""&gt;Point3DSlot&lt;/text&gt;&lt;/g&gt;&lt;g class="guides"&gt;&lt;path d="M501.825641 0.000000 v514.000000" class="guide line"&gt;&lt;/path&gt;&lt;text x="501.82564102564106" y="529.0" class=""&gt;Point3DSlot Uncached Integers&lt;/text&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class="series serie-0 color-0"&gt;&lt;g class="bars"&gt;&lt;g class="bar"&gt;&lt;rect x="25.00167032967033" y="405.0917639537655" rx="0" ry="0" width="21.68603663003663" height="99.02362066161913" class="rect reactive tooltip-trigger"&gt;&lt;/rect&gt;&lt;desc class="value"&gt;691.9&lt;/desc&gt;&lt;desc class="x centered"&gt;35.844688644688645&lt;/desc&gt;&lt;desc class="y centered"&gt;454.6035742845751&lt;/desc&gt;&lt;desc class="x_label"&gt;Point3D&lt;/desc&gt;&lt;/g&gt;&lt;g class="bar"&gt;&lt;rect x="221.02731135531135" y="405.07745211380865" rx="0" ry="0" width="21.68603663003663" height="99.037932501576" class="rect reactive tooltip-trigger"&gt;&lt;/rect&gt;&lt;desc class="value"&gt;692&lt;/desc&gt;&lt;desc class="x centered"&gt;231.87032967032968&lt;/desc&gt;&lt;desc class="y centered"&gt;454.5964183645966&lt;/desc&gt;&lt;desc class="x_label"&gt;Point3DSlot&lt;/desc&gt;&lt;/g&gt;&lt;g class="bar"&gt;&lt;rect x="417.0529523809524" y="339.2143646322692" rx="0" ry="0" width="21.68603663003663" height="164.90101998311542" class="rect reactive tooltip-trigger"&gt;&lt;/rect&gt;&lt;desc class="value"&gt;1152.2&lt;/desc&gt;&lt;desc class="x centered"&gt;427.8959706959707&lt;/desc&gt;&lt;desc class="y centered"&gt;421.6648746238269&lt;/desc&gt;&lt;desc class="x_label"&gt;Point3DSlot Uncached Integers&lt;/desc&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class="series serie-1 color-1"&gt;&lt;g class="bars"&gt;&lt;g class="bar"&gt;&lt;rect x="49.64489377289377" y="406.27964667018614" rx="0" ry="0" width="21.68603663003663" height="97.8357379451985" class="rect reactive tooltip-trigger"&gt;&lt;/rect&gt;&lt;desc class="value"&gt;683.6&lt;/desc&gt;&lt;desc class="x centered"&gt;60.48791208791208&lt;/desc&gt;&lt;desc class="y centered"&gt;455.1975156427854&lt;/desc&gt;&lt;desc class="x_label"&gt;Point3D&lt;/desc&gt;&lt;/g&gt;&lt;g class="bar"&gt;&lt;rect x="245.6705347985348" y="406.2510229902724" rx="0" ry="0" width="21.68603663003663" height="97.86436162511222" class="rect reactive tooltip-trigger"&gt;&lt;/rect&gt;&lt;desc class="value"&gt;683.8&lt;/desc&gt;&lt;desc class="x centered"&gt;256.5135531135531&lt;/desc&gt;&lt;desc class="y centered"&gt;455.18320380282853&lt;/desc&gt;&lt;desc class="x_label"&gt;Point3DSlot&lt;/desc&gt;&lt;/g&gt;&lt;g class="bar"&gt;&lt;rect x="441.69617582417584" y="340.44947642054757" rx="0" ry="0" width="21.68603663003663" height="163.66590819483707" class="rect reactive tooltip-trigger"&gt;&lt;/rect&gt;&lt;desc class="value"&gt;1143.57&lt;/desc&gt;&lt;desc class="x centered"&gt;452.53919413919414&lt;/desc&gt;&lt;desc class="y centered"&gt;422.2824305179661&lt;/desc&gt;&lt;desc class="x_label"&gt;Point3DSlot Uncached Integers&lt;/desc&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class="series serie-2 color-2"&gt;&lt;g class="bars"&gt;&lt;g class="bar"&gt;&lt;rect x="74.2881172161172" y="9.884615384615358" rx="0" ry="0" width="21.68603663003663" height="494.2307692307693" class="rect reactive tooltip-trigger"&gt;&lt;/rect&gt;&lt;desc class="value"&gt;3453.3&lt;/desc&gt;&lt;desc class="x centered"&gt;85.13113553113551&lt;/desc&gt;&lt;desc class="y centered"&gt;257.0&lt;/desc&gt;&lt;desc class="x_label"&gt;Point3D&lt;/desc&gt;&lt;/g&gt;&lt;g class="bar"&gt;&lt;rect x="270.31375824175825" y="391.349535227174" rx="0" ry="0" width="21.68603663003663" height="112.76584938821065" class="rect reactive tooltip-trigger"&gt;&lt;/rect&gt;&lt;desc class="value"&gt;787.92&lt;/desc&gt;&lt;desc class="x centered"&gt;281.15677655677655&lt;/desc&gt;&lt;desc class="y centered"&gt;447.7324599212793&lt;/desc&gt;&lt;desc class="x_label"&gt;Point3DSlot&lt;/desc&gt;&lt;/g&gt;&lt;g class="bar"&gt;&lt;rect x="466.33939926739924" y="271.5909208360342" rx="0" ry="0" width="21.68603663003663" height="232.52446377935047" class="rect reactive tooltip-trigger"&gt;&lt;/rect&gt;&lt;desc class="value"&gt;1624.7&lt;/desc&gt;&lt;desc class="x centered"&gt;477.18241758241754&lt;/desc&gt;&lt;desc class="y centered"&gt;387.8531527257094&lt;/desc&gt;&lt;desc class="x_label"&gt;Point3DSlot Uncached Integers&lt;/desc&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class="series serie-3 color-3"&gt;&lt;g class="bars"&gt;&lt;g class="bar"&gt;&lt;rect x="98.93134065934066" y="286.37505151148616" rx="0" ry="0" width="21.68603663003663" height="217.74033310389848" class="rect reactive tooltip-trigger"&gt;&lt;/rect&gt;&lt;desc class="value"&gt;1521.4&lt;/desc&gt;&lt;desc class="x centered"&gt;109.77435897435898&lt;/desc&gt;&lt;desc class="y centered"&gt;395.2452180634354&lt;/desc&gt;&lt;desc class="x_label"&gt;Point3D&lt;/desc&gt;&lt;/g&gt;&lt;g class="bar"&gt;&lt;rect x="294.95698168498166" y="402.6158156412261" rx="0" ry="0" width="21.68603663003663" height="101.49956897415854" class="rect reactive tooltip-trigger"&gt;&lt;/rect&gt;&lt;desc class="value"&gt;709.2&lt;/desc&gt;&lt;desc class="x centered"&gt;305.79999999999995&lt;/desc&gt;&lt;desc class="y centered"&gt;453.36560012830535&lt;/desc&gt;&lt;desc class="x_label"&gt;Point3DSlot&lt;/desc&gt;&lt;/g&gt;&lt;g class="bar"&gt;&lt;rect x="490.9826227106227" y="271.6138197799652" rx="0" ry="0" width="21.68603663003663" height="232.50156483541946" class="rect reactive tooltip-trigger"&gt;&lt;/rect&gt;&lt;desc class="value"&gt;1624.54&lt;/desc&gt;&lt;desc class="x centered"&gt;501.825641025641&lt;/desc&gt;&lt;desc class="y centered"&gt;387.8646021976749&lt;/desc&gt;&lt;desc class="x_label"&gt;Point3DSlot Uncached Integers&lt;/desc&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class="series serie-4 color-4"&gt;&lt;g class="bars"&gt;&lt;g class="bar"&gt;&lt;rect x="123.5745641025641" y="282.84002704213805" rx="0" ry="0" width="21.68603663003663" height="221.2753575732466" class="rect reactive tooltip-trigger"&gt;&lt;/rect&gt;&lt;desc class="value"&gt;1546.1&lt;/desc&gt;&lt;desc class="x centered"&gt;134.41758241758242&lt;/desc&gt;&lt;desc class="y centered"&gt;393.4777058287614&lt;/desc&gt;&lt;desc class="x_label"&gt;Point3D&lt;/desc&gt;&lt;/g&gt;&lt;g class="bar"&gt;&lt;rect x="319.6002051282051" y="402.6444393211399" rx="0" ry="0" width="21.68603663003663" height="101.47094529424476" class="rect reactive tooltip-trigger"&gt;&lt;/rect&gt;&lt;desc class="value"&gt;709&lt;/desc&gt;&lt;desc class="x centered"&gt;330.4432234432234&lt;/desc&gt;&lt;desc class="y centered"&gt;453.37991196826226&lt;/desc&gt;&lt;desc class="x_label"&gt;Point3DSlot&lt;/desc&gt;&lt;/g&gt;&lt;g class="bar"&gt;&lt;rect x="515.6258461538462" y="271.5909208360342" rx="0" ry="0" width="21.68603663003663" height="232.52446377935047" class="rect reactive tooltip-trigger"&gt;&lt;/rect&gt;&lt;desc class="value"&gt;1624.7&lt;/desc&gt;&lt;desc class="x centered"&gt;526.4688644688645&lt;/desc&gt;&lt;desc class="y centered"&gt;387.8531527257094&lt;/desc&gt;&lt;desc class="x_label"&gt;Point3DSlot Uncached Integers&lt;/desc&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class="series serie-5 color-5"&gt;&lt;g class="bars"&gt;&lt;g class="bar"&gt;&lt;rect x="148.21778754578753" y="286.24624495187436" rx="0" ry="0" width="21.68603663003663" height="217.86913966351028" class="rect reactive tooltip-trigger"&gt;&lt;/rect&gt;&lt;desc class="value"&gt;1522.3&lt;/desc&gt;&lt;desc class="x centered"&gt;159.06080586080586&lt;/desc&gt;&lt;desc class="y centered"&gt;395.1808147836295&lt;/desc&gt;&lt;desc class="x_label"&gt;Point3D&lt;/desc&gt;&lt;/g&gt;&lt;g class="bar"&gt;&lt;rect x="344.2434285714286" y="403.31709579911296" rx="0" ry="0" width="21.68603663003663" height="100.79828881627168" class="rect reactive tooltip-trigger"&gt;&lt;/rect&gt;&lt;desc class="value"&gt;704.3&lt;/desc&gt;&lt;desc class="x centered"&gt;355.0864468864469&lt;/desc&gt;&lt;desc class="y centered"&gt;453.7162402072488&lt;/desc&gt;&lt;desc class="x_label"&gt;Point3DSlot&lt;/desc&gt;&lt;/g&gt;&lt;g class="bar"&gt;&lt;rect x="540.2690695970696" y="271.5766089960773" rx="0" ry="0" width="21.68603663003663" height="232.53877561930733" class="rect reactive tooltip-trigger"&gt;&lt;/rect&gt;&lt;desc class="value"&gt;1624.8&lt;/desc&gt;&lt;desc class="x centered"&gt;551.1120879120879&lt;/desc&gt;&lt;desc class="y centered"&gt;387.845996805731&lt;/desc&gt;&lt;desc class="x_label"&gt;Point3DSlot Uncached Integers&lt;/desc&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class="series serie-6 color-6"&gt;&lt;g class="bars"&gt;&lt;g class="bar"&gt;&lt;rect x="172.861010989011" y="195.7095453846822" rx="0" ry="0" width="21.68603663003663" height="308.40583923070244" class="rect reactive tooltip-trigger"&gt;&lt;/rect&gt;&lt;desc class="value"&gt;2154.9&lt;/desc&gt;&lt;desc class="x centered"&gt;183.70402930402932&lt;/desc&gt;&lt;desc class="y centered"&gt;349.9124650000334&lt;/desc&gt;&lt;desc class="x_label"&gt;Point3D&lt;/desc&gt;&lt;/g&gt;&lt;g class="bar"&gt;&lt;rect x="368.886652014652" y="359.6230484107732" rx="0" ry="0" width="21.68603663003663" height="144.49233620461143" class="rect reactive tooltip-trigger"&gt;&lt;/rect&gt;&lt;desc class="value"&gt;1009.6&lt;/desc&gt;&lt;desc class="x centered"&gt;379.7296703296703&lt;/desc&gt;&lt;desc class="y centered"&gt;431.8692165130789&lt;/desc&gt;&lt;desc class="x_label"&gt;Point3DSlot&lt;/desc&gt;&lt;/g&gt;&lt;g class="bar"&gt;&lt;rect x="564.9122930402931" y="93.42282521289559" rx="0" ry="0" width="21.68603663003663" height="410.69255940248905" class="rect reactive tooltip-trigger"&gt;&lt;/rect&gt;&lt;desc class="value"&gt;2869.6&lt;/desc&gt;&lt;desc class="x centered"&gt;575.7553113553114&lt;/desc&gt;&lt;desc class="y centered"&gt;298.76910491414014&lt;/desc&gt;&lt;desc class="x_label"&gt;Point3DSlot Uncached Integers&lt;/desc&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class="titles"&gt;&lt;text x="400.0" y="26" class="title plot_title"&gt;Memory Usage (in MB)&lt;/text&gt;&lt;/g&gt;&lt;g transform="translate(168, 46)" class="plot overlay"&gt;&lt;g class="series serie-0 color-0"&gt;&lt;/g&gt;&lt;g class="series serie-1 color-1"&gt;&lt;/g&gt;&lt;g class="series serie-2 color-2"&gt;&lt;/g&gt;&lt;g class="series serie-3 color-3"&gt;&lt;/g&gt;&lt;g class="series serie-4 color-4"&gt;&lt;/g&gt;&lt;g class="series serie-5 color-5"&gt;&lt;/g&gt;&lt;g class="series serie-6 color-6"&gt;&lt;/g&gt;&lt;/g&gt;&lt;g transform="translate(168, 46)" class="plot text-overlay"&gt;&lt;g class="series serie-0 color-0"&gt;&lt;/g&gt;&lt;g class="series serie-1 color-1"&gt;&lt;/g&gt;&lt;g class="series serie-2 color-2"&gt;&lt;/g&gt;&lt;g class="series serie-3 color-3"&gt;&lt;/g&gt;&lt;g class="series serie-4 color-4"&gt;&lt;/g&gt;&lt;g class="series serie-5 color-5"&gt;&lt;/g&gt;&lt;g class="series serie-6 color-6"&gt;&lt;/g&gt;&lt;/g&gt;&lt;g transform="translate(168, 46)" class="plot tooltip-overlay"&gt;&lt;g transform="translate(0 0)" style="opacity: 0" class="tooltip"&gt;&lt;rect rx="0" ry="0" width="0" height="0" class="tooltip-box"&gt;&lt;/rect&gt;&lt;g class="text"&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g transform="translate(10, 56)" class="legends"&gt;&lt;g id="activate-serie-0" class="legend reactive activate-serie"&gt;&lt;rect x="0.0" y="1.0" width="12" height="12" class="color-0 reactive"&gt;&lt;/rect&gt;&lt;text x="17.0" y="11.2"&gt;PyPy2&lt;/text&gt;&lt;/g&gt;&lt;g id="activate-serie-1" class="legend reactive activate-serie"&gt;&lt;rect x="0.0" y="22.0" width="12" height="12" class="color-1 reactive"&gt;&lt;/rect&gt;&lt;text x="17.0" y="32.2"&gt;PyPy3&lt;/text&gt;&lt;/g&gt;&lt;g id="activate-serie-2" class="legend reactive activate-serie"&gt;&lt;rect x="0.0" y="43.0" width="12" height="12" class="color-2 reactive"&gt;&lt;/rect&gt;&lt;text x="17.0" y="53.2"&gt;CPython 2.7&lt;/text&gt;&lt;/g&gt;&lt;g id="activate-serie-3" class="legend reactive activate-serie"&gt;&lt;rect x="0.0" y="64.0" width="12" height="12" class="color-3 reactive"&gt;&lt;/rect&gt;&lt;text x="17.0" y="74.2"&gt;CPython 3.4&lt;/text&gt;&lt;/g&gt;&lt;g id="activate-serie-4" class="legend reactive activate-serie"&gt;&lt;rect x="0.0" y="85.0" width="12" height="12" class="color-4 reactive"&gt;&lt;/rect&gt;&lt;text x="17.0" y="95.2"&gt;CPython 3.5&lt;/text&gt;&lt;/g&gt;&lt;g id="activate-serie-5" class="legend reactive activate-serie"&gt;&lt;rect x="0.0" y="106.0" width="12" height="12" class="color-5 reactive"&gt;&lt;/rect&gt;&lt;text x="17.0" y="116.2"&gt;CPython 3.6&lt;/text&gt;&lt;/g&gt;&lt;g id="activate-serie-6" class="legend reactive activate-serie"&gt;&lt;rect x="0.0" y="127.0" width="12" height="12" class="color-6 reactive"&gt;&lt;/rect&gt;&lt;text x="17.0" y="137.2"&gt;CPython 3.7&lt;/text&gt;&lt;/g&gt;&lt;/g&gt;&lt;g transform="translate(790, 56)" class="legends"&gt;&lt;/g&gt;&lt;/g&gt;&lt;/svg&gt;&lt;p&gt;The third group of data is the same as the second group, except
instead of using small integers that should be in the CPython internal
integer object cache &lt;a class="footnote-reference" href="https://seecoresoftware.com/blog/2018/08/cpython-vs-pypy-memory-usage.html#f7" id="id3"&gt;[7]&lt;/a&gt;, I used larger numbers that shouldn't be
cached. This is just an interesting data point showing the allocation
of three times as many objects, and won't be discussed further.&lt;/p&gt;
&lt;!-- A link to 'Do Re Mi' from the Sound of Music: "Let's start at the
very beginning, a very good place to start." --&gt;
&lt;div class="section" id="what-is-being-measured"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="https://seecoresoftware.com/blog/2018/08/cpython-vs-pypy-memory-usage.html#id9"&gt;What Is Being Measured&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In the script I used to produce these numbers &lt;a class="footnote-reference" href="https://seecoresoftware.com/blog/2018/08/cpython-vs-pypy-memory-usage.html#f2" id="id4"&gt;[2]&lt;/a&gt;, I'm using the
excellent psutil library's &lt;a class="reference external" href="http://psutil.readthedocs.io/en/latest/#psutil.Process.memory_full_info"&gt;Process.memory_info&lt;/a&gt; to record the
"unique set size" ("the memory which is unique to a process and which
would be freed if the process was terminated right now") before and
then after allocating a large number of objects.&lt;/p&gt;
&lt;pre class="code python"&gt;&lt;a name="rest_code_987899094c92461da96de736c74b6b89-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;klass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a name="rest_code_987899094c92461da96de736c74b6b89-2"&gt;&lt;/a&gt;    &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_memory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uss&lt;/span&gt;
&lt;a name="rest_code_987899094c92461da96de736c74b6b89-3"&gt;&lt;/a&gt;    &lt;span class="n"&gt;inst&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;klass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a name="rest_code_987899094c92461da96de736c74b6b89-4"&gt;&lt;/a&gt;    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Size of"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sizeof_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inst&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;a name="rest_code_987899094c92461da96de736c74b6b89-5"&gt;&lt;/a&gt;    &lt;span class="k"&gt;del&lt;/span&gt; &lt;span class="n"&gt;inst&lt;/span&gt;
&lt;a name="rest_code_987899094c92461da96de736c74b6b89-6"&gt;&lt;/a&gt;
&lt;a name="rest_code_987899094c92461da96de736c74b6b89-7"&gt;&lt;/a&gt;    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Count      AbsoluteUsage     Delta"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a name="rest_code_987899094c92461da96de736c74b6b89-8"&gt;&lt;/a&gt;    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"======================================="&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a name="rest_code_987899094c92461da96de736c74b6b89-9"&gt;&lt;/a&gt;
&lt;a name="rest_code_987899094c92461da96de736c74b6b89-10"&gt;&lt;/a&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10000000&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a name="rest_code_987899094c92461da96de736c74b6b89-11"&gt;&lt;/a&gt;        &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;
&lt;a name="rest_code_987899094c92461da96de736c74b6b89-12"&gt;&lt;/a&gt;
&lt;a name="rest_code_987899094c92461da96de736c74b6b89-13"&gt;&lt;/a&gt;        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a name="rest_code_987899094c92461da96de736c74b6b89-14"&gt;&lt;/a&gt;            &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;klass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a name="rest_code_987899094c92461da96de736c74b6b89-15"&gt;&lt;/a&gt;
&lt;a name="rest_code_987899094c92461da96de736c74b6b89-16"&gt;&lt;/a&gt;        &lt;span class="n"&gt;after&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_memory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uss&lt;/span&gt;
&lt;a name="rest_code_987899094c92461da96de736c74b6b89-17"&gt;&lt;/a&gt;        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;%9d&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;format_memory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;after&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;global_starting_memory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uss&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;a name="rest_code_987899094c92461da96de736c74b6b89-18"&gt;&lt;/a&gt;              &lt;span class="n"&gt;format_memory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;after&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;a name="rest_code_987899094c92461da96de736c74b6b89-19"&gt;&lt;/a&gt;        &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;a name="rest_code_987899094c92461da96de736c74b6b89-20"&gt;&lt;/a&gt;    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;p&gt;This gives us a fairly accurate idea of how much memory the processes
needed to allocate from the operating system to be able to create all
the objects we asked for. (&lt;tt class="docutils literal"&gt;get_memory&lt;/tt&gt; is a helper function that
runs the garbage collector to be sure we have the most stable
numbers.)&lt;/p&gt;
&lt;div class="section" id="what-is-not-being-measured"&gt;
&lt;h3&gt;&lt;a class="toc-backref" href="https://seecoresoftware.com/blog/2018/08/cpython-vs-pypy-memory-usage.html#id10"&gt;What Is Not Being Measured&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In this example output from a run of PyPy, the &lt;tt class="docutils literal"&gt;AbsoluteUsage&lt;/tt&gt; is
the total growth from when the program started, while the &lt;tt class="docutils literal"&gt;Delta&lt;/tt&gt; is
the growth just within this function.&lt;/p&gt;
&lt;pre class="code text"&gt;&lt;a name="rest_code_abea1e7bbd544248b67bbed92ef5690b-1"&gt;&lt;/a&gt;Memory for Point3D(1, 2, 3)
&lt;a name="rest_code_abea1e7bbd544248b67bbed92ef5690b-2"&gt;&lt;/a&gt;Count      AbsoluteUsage     Delta
&lt;a name="rest_code_abea1e7bbd544248b67bbed92ef5690b-3"&gt;&lt;/a&gt;=======================================
&lt;a name="rest_code_abea1e7bbd544248b67bbed92ef5690b-4"&gt;&lt;/a&gt;      100           0.02           0.02
&lt;a name="rest_code_abea1e7bbd544248b67bbed92ef5690b-5"&gt;&lt;/a&gt;     1000           0.03           0.03
&lt;a name="rest_code_abea1e7bbd544248b67bbed92ef5690b-6"&gt;&lt;/a&gt;    10000           0.51           0.51
&lt;a name="rest_code_abea1e7bbd544248b67bbed92ef5690b-7"&gt;&lt;/a&gt;   100000           7.20           7.20
&lt;a name="rest_code_abea1e7bbd544248b67bbed92ef5690b-8"&gt;&lt;/a&gt;  1000000          69.11          69.11
&lt;a name="rest_code_abea1e7bbd544248b67bbed92ef5690b-9"&gt;&lt;/a&gt; 10000000         691.90         691.90
&lt;/pre&gt;&lt;p&gt;This was the first of the test runs within this particular process.
The second test run within this process reports higher absolute deltas
since the beginning of the program, although the overall deltas are
smaller. This indicates how much memory the program has allocated from
the operating system but not returned to it, even though it may
technically free from the standpoint of the Python runtime; this
accounts for things like internal caches, or in PyPy's case, jitted
code.&lt;/p&gt;
&lt;pre class="code text"&gt;&lt;a name="rest_code_7993a3a16f054fb88b67afc16912f188-1"&gt;&lt;/a&gt;Memory for Point3DSlot(1, 2, 3)
&lt;a name="rest_code_7993a3a16f054fb88b67afc16912f188-2"&gt;&lt;/a&gt;Size of Point3DSlot -1
&lt;a name="rest_code_7993a3a16f054fb88b67afc16912f188-3"&gt;&lt;/a&gt;Count      AbsoluteUsage     Delta
&lt;a name="rest_code_7993a3a16f054fb88b67afc16912f188-4"&gt;&lt;/a&gt;=======================================
&lt;a name="rest_code_7993a3a16f054fb88b67afc16912f188-5"&gt;&lt;/a&gt;      100          86.09           0.00
&lt;a name="rest_code_7993a3a16f054fb88b67afc16912f188-6"&gt;&lt;/a&gt;     1000          86.12           0.03
&lt;a name="rest_code_7993a3a16f054fb88b67afc16912f188-7"&gt;&lt;/a&gt;    10000          86.56           0.46
&lt;a name="rest_code_7993a3a16f054fb88b67afc16912f188-8"&gt;&lt;/a&gt;   100000          87.33           1.23
&lt;a name="rest_code_7993a3a16f054fb88b67afc16912f188-9"&gt;&lt;/a&gt;  1000000         138.70          52.60
&lt;a name="rest_code_7993a3a16f054fb88b67afc16912f188-10"&gt;&lt;/a&gt; 10000000         692.05         605.95
&lt;/pre&gt;&lt;p&gt;Although I captured the data, this post is not about the startup or
initial memory allocation of the various interpreters, nor about how
much can easily be shared between forked processes, nor about how much
memory is returned to the operating system while the process is still
running. We're only talking about the memory size needed to allocate a
given number of objects, e.g., the &lt;tt class="docutils literal"&gt;Delta&lt;/tt&gt; column.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="object-internals"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="https://seecoresoftware.com/blog/2018/08/cpython-vs-pypy-memory-usage.html#id11"&gt;Object Internals&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To understand what's happening, let's look at the two types of objects
we're comparing:&lt;/p&gt;
&lt;pre class="code python"&gt;&lt;a name="rest_code_8e9442e5c8044e6e9d61b819a8739b43-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Point3D&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a name="rest_code_8e9442e5c8044e6e9d61b819a8739b43-2"&gt;&lt;/a&gt;
&lt;a name="rest_code_8e9442e5c8044e6e9d61b819a8739b43-3"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a name="rest_code_8e9442e5c8044e6e9d61b819a8739b43-4"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;
&lt;a name="rest_code_8e9442e5c8044e6e9d61b819a8739b43-5"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;
&lt;a name="rest_code_8e9442e5c8044e6e9d61b819a8739b43-6"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;
&lt;a name="rest_code_8e9442e5c8044e6e9d61b819a8739b43-7"&gt;&lt;/a&gt;
&lt;a name="rest_code_8e9442e5c8044e6e9d61b819a8739b43-8"&gt;&lt;/a&gt;
&lt;a name="rest_code_8e9442e5c8044e6e9d61b819a8739b43-9"&gt;&lt;/a&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Point3DSlot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a name="rest_code_8e9442e5c8044e6e9d61b819a8739b43-10"&gt;&lt;/a&gt;    &lt;span class="vm"&gt;__slots__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'x'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'y'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'z'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a name="rest_code_8e9442e5c8044e6e9d61b819a8739b43-11"&gt;&lt;/a&gt;
&lt;a name="rest_code_8e9442e5c8044e6e9d61b819a8739b43-12"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a name="rest_code_8e9442e5c8044e6e9d61b819a8739b43-13"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;
&lt;a name="rest_code_8e9442e5c8044e6e9d61b819a8739b43-14"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;
&lt;a name="rest_code_8e9442e5c8044e6e9d61b819a8739b43-15"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;
&lt;/pre&gt;&lt;p&gt;These are both small classes with three instance attributes. One is a
standard, default, object, and one specifies its instance attributes
in &lt;tt class="docutils literal"&gt;__slots__&lt;/tt&gt;.&lt;/p&gt;
&lt;div class="section" id="objects-with-dictionaries"&gt;
&lt;h3&gt;&lt;a class="toc-backref" href="https://seecoresoftware.com/blog/2018/08/cpython-vs-pypy-memory-usage.html#id12"&gt;Objects with Dictionaries&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Standard objects, like &lt;tt class="docutils literal"&gt;Point3D&lt;/tt&gt;, have &lt;a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#object.__dict__"&gt;a special attribute&lt;/a&gt;
&lt;tt class="docutils literal"&gt;__dict__&lt;/tt&gt;, that is a normal Python dictionary object that is used
to hold all the instance attributes for the object. We &lt;a class="reference external" href="https://seecoresoftware.com/blog/2018/07/python-2-new-vs-old-classes.html#old-style-classes-ignore-getattribute"&gt;previously
looked at&lt;/a&gt;
how &lt;tt class="docutils literal"&gt;__getattribute__&lt;/tt&gt; can be used to customize &lt;em&gt;all&lt;/em&gt; attribute
reads for an object; likewise, &lt;tt class="docutils literal"&gt;__setattr__&lt;/tt&gt; can &lt;a class="reference external" href="https://docs.python.org/3/reference/datamodel.html?highlight=__slots__#object.__setattr__"&gt;customize all
attribute writes&lt;/a&gt;. The default &lt;tt class="docutils literal"&gt;__getattribute__&lt;/tt&gt; and
&lt;tt class="docutils literal"&gt;__setattr__&lt;/tt&gt; that a class inherits from &lt;tt class="docutils literal"&gt;object&lt;/tt&gt; function
something like they were written to access the &lt;tt class="docutils literal"&gt;__dict__&lt;/tt&gt;:&lt;/p&gt;
&lt;pre class="code python"&gt;&lt;a name="rest_code_35364c4900ba43f6989e0f32507241fe-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a name="rest_code_35364c4900ba43f6989e0f32507241fe-2"&gt;&lt;/a&gt;
&lt;a name="rest_code_35364c4900ba43f6989e0f32507241fe-3"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__getattribute__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a name="rest_code_35364c4900ba43f6989e0f32507241fe-4"&gt;&lt;/a&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__dict__&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a name="rest_code_35364c4900ba43f6989e0f32507241fe-5"&gt;&lt;/a&gt;             &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__dict__&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;a name="rest_code_35364c4900ba43f6989e0f32507241fe-6"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a name="rest_code_35364c4900ba43f6989e0f32507241fe-7"&gt;&lt;/a&gt;
&lt;a name="rest_code_35364c4900ba43f6989e0f32507241fe-8"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__setattr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a name="rest_code_35364c4900ba43f6989e0f32507241fe-9"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__dict__&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
&lt;/pre&gt;&lt;p&gt;One advantage of having a &lt;tt class="docutils literal"&gt;__dict__&lt;/tt&gt; underlying an object is the
flexibility it provides: you don't have to pre-declare your attributes
for every object, and any object can have any attribute, so it
facilitates subclasses adding new attributes, or even other libraries
adding new, specialized, attributes to &lt;a class="reference external" href="https://github.com/zopefoundation/zope.cachedescriptors/blob/master/src/zope/cachedescriptors/property.py#L60"&gt;implement caching of expensive
computed properties&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One disadvantage is that a &lt;tt class="docutils literal"&gt;__dict__&lt;/tt&gt; is a generic Python
dictionary, not specialized at all &lt;a class="footnote-reference" href="https://seecoresoftware.com/blog/2018/08/cpython-vs-pypy-memory-usage.html#f3" id="id5"&gt;[3]&lt;/a&gt;, and as such it has overhead.&lt;/p&gt;
&lt;p&gt;On CPython, we can ask the interpreter how much memory any given
object uses with &lt;a class="reference external" href="https://docs.python.org/3/library/sys.html?highlight=getsizeof#sys.getsizeof"&gt;sys.getsizeof&lt;/a&gt;. On my machine under a 64-bit
CPython 2.7.15, a bare &lt;tt class="docutils literal"&gt;object&lt;/tt&gt; takes 16 bytes, while a trivial
subclass takes a full 64 bytes (due to the overhead of being tracked
by the garbage collector):&lt;/p&gt;
&lt;pre class="code pycon"&gt;&lt;a name="rest_code_15c85954908d4deea792def9308294e8-1"&gt;&lt;/a&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt;
&lt;a name="rest_code_15c85954908d4deea792def9308294e8-2"&gt;&lt;/a&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getsizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;a name="rest_code_15c85954908d4deea792def9308294e8-3"&gt;&lt;/a&gt;&lt;span class="go"&gt;16&lt;/span&gt;
&lt;a name="rest_code_15c85954908d4deea792def9308294e8-4"&gt;&lt;/a&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TrivialSubclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;a name="rest_code_15c85954908d4deea792def9308294e8-5"&gt;&lt;/a&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getsizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TriviasSubclass&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;a name="rest_code_15c85954908d4deea792def9308294e8-6"&gt;&lt;/a&gt;&lt;span class="go"&gt;64&lt;/span&gt;
&lt;/pre&gt;&lt;p&gt;An empty &lt;tt class="docutils literal"&gt;dict&lt;/tt&gt; occupies 280 bytes:&lt;/p&gt;
&lt;pre class="code pycon"&gt;&lt;a name="rest_code_760e244c17cc4461bd35fcf1c2a071a4-1"&gt;&lt;/a&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getsizeof&lt;/span&gt;&lt;span class="p"&gt;({})&lt;/span&gt;
&lt;a name="rest_code_760e244c17cc4461bd35fcf1c2a071a4-2"&gt;&lt;/a&gt;&lt;span class="go"&gt;280&lt;/span&gt;
&lt;/pre&gt;&lt;p&gt;And so when you combine the size of the trivial subclass, with the
size of its &lt;tt class="docutils literal"&gt;__dict__&lt;/tt&gt; you arrive at a minimum object size of 344
bytes:&lt;/p&gt;
&lt;pre class="code pycon"&gt;&lt;a name="rest_code_6bd67988897f4e7aa9efb4ae67d5cd9b-1"&gt;&lt;/a&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getsizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TrivialSubclass&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__dict__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a name="rest_code_6bd67988897f4e7aa9efb4ae67d5cd9b-2"&gt;&lt;/a&gt;&lt;span class="go"&gt;280&lt;/span&gt;
&lt;a name="rest_code_6bd67988897f4e7aa9efb4ae67d5cd9b-3"&gt;&lt;/a&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getsizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TrivialSubclass&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getsizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TrivialSubclass&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__dict__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a name="rest_code_6bd67988897f4e7aa9efb4ae67d5cd9b-4"&gt;&lt;/a&gt;&lt;span class="go"&gt;344&lt;/span&gt;
&lt;/pre&gt;&lt;p&gt;A fully occupied &lt;tt class="docutils literal"&gt;Point3D&lt;/tt&gt; object is also 344 bytes:&lt;/p&gt;
&lt;pre class="code pycon"&gt;&lt;a name="rest_code_5aa26ad4ef524067a5faaf256fbf198a-1"&gt;&lt;/a&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Point3D&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a name="rest_code_5aa26ad4ef524067a5faaf256fbf198a-2"&gt;&lt;/a&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getsizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getsizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__dict__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a name="rest_code_5aa26ad4ef524067a5faaf256fbf198a-3"&gt;&lt;/a&gt;&lt;span class="go"&gt;344&lt;/span&gt;
&lt;/pre&gt;&lt;p&gt;Because of the way dictionaries are implemented &lt;a class="footnote-reference" href="https://seecoresoftware.com/blog/2018/08/cpython-vs-pypy-memory-usage.html#f8" id="id6"&gt;[8]&lt;/a&gt;, there's always a
little spare room for extra attributes. We don't find a jump in size
until we've added three more attributes:&lt;/p&gt;
&lt;pre class="code pycon"&gt;&lt;a name="rest_code_84331c6c162b4d0aa0fc2988f2269d64-1"&gt;&lt;/a&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;a name="rest_code_84331c6c162b4d0aa0fc2988f2269d64-2"&gt;&lt;/a&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getsizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getsizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__dict__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a name="rest_code_84331c6c162b4d0aa0fc2988f2269d64-3"&gt;&lt;/a&gt;&lt;span class="go"&gt;344&lt;/span&gt;
&lt;a name="rest_code_84331c6c162b4d0aa0fc2988f2269d64-4"&gt;&lt;/a&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;a name="rest_code_84331c6c162b4d0aa0fc2988f2269d64-5"&gt;&lt;/a&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getsizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getsizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__dict__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a name="rest_code_84331c6c162b4d0aa0fc2988f2269d64-6"&gt;&lt;/a&gt;&lt;span class="go"&gt;344&lt;/span&gt;
&lt;a name="rest_code_84331c6c162b4d0aa0fc2988f2269d64-7"&gt;&lt;/a&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;a name="rest_code_84331c6c162b4d0aa0fc2988f2269d64-8"&gt;&lt;/a&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getsizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getsizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__dict__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a name="rest_code_84331c6c162b4d0aa0fc2988f2269d64-9"&gt;&lt;/a&gt;&lt;span class="go"&gt;1112&lt;/span&gt;
&lt;/pre&gt;&lt;div class="admonition note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p class="last"&gt;These values can change quite a bit across Python versions,
typically improving over time. In CPython 3.4 and 3.5,
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;getsizeof({})&lt;/span&gt;&lt;/tt&gt; returns 288, while it returns 240 in both 3.6 and
3.7. In addition, &lt;tt class="docutils literal"&gt;getsizeof(pd.__dict__)&lt;/tt&gt; returns 96 and 112
&lt;a class="footnote-reference" href="https://seecoresoftware.com/blog/2018/08/cpython-vs-pypy-memory-usage.html#f4" id="id7"&gt;[4]&lt;/a&gt;. The answer to &lt;tt class="docutils literal"&gt;getsizeof(pd)&lt;/tt&gt; is 56 in all four versions.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="objects-with-slots"&gt;
&lt;h3&gt;&lt;a class="toc-backref" href="https://seecoresoftware.com/blog/2018/08/cpython-vs-pypy-memory-usage.html#id13"&gt;Objects With Slots&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Objects with a &lt;tt class="docutils literal"&gt;__slots__&lt;/tt&gt; declaration, like &lt;tt class="docutils literal"&gt;Point3DSlot&lt;/tt&gt; do not
have a &lt;tt class="docutils literal"&gt;__dict__&lt;/tt&gt; by default. &lt;a class="reference external" href="https://docs.python.org/3/reference/datamodel.html?highlight=__slots__#slots"&gt;The documentation&lt;/a&gt; notes that this
can be a space savings. Indeed, on CPython 2.7, a &lt;tt class="docutils literal"&gt;Point3DSlot&lt;/tt&gt; has
a size of only 72 bytes, only one full pointer larger than a trivial
subclass (when we do not factor in the &lt;tt class="docutils literal"&gt;__dict__&lt;/tt&gt;):&lt;/p&gt;
&lt;pre class="code pycon"&gt;&lt;a name="rest_code_d017747e3a124be2b2826720fa3695b0-1"&gt;&lt;/a&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;pds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Point3DSlot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a name="rest_code_d017747e3a124be2b2826720fa3695b0-2"&gt;&lt;/a&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getsizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a name="rest_code_d017747e3a124be2b2826720fa3695b0-3"&gt;&lt;/a&gt;&lt;span class="go"&gt;72&lt;/span&gt;
&lt;/pre&gt;&lt;p&gt;If they don't have an instance dictionary, where do they store their
attributes? And why, if &lt;tt class="docutils literal"&gt;Point3DSlot&lt;/tt&gt; has &lt;em&gt;three&lt;/em&gt; defined
attributes, is it only &lt;em&gt;one&lt;/em&gt; pointer larger than &lt;tt class="docutils literal"&gt;Point3D&lt;/tt&gt;?&lt;/p&gt;
&lt;p&gt;Slots, like &lt;tt class="docutils literal"&gt;@property&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;@classmethod&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;@staticmethod&lt;/tt&gt;, are
implemented using &lt;a class="reference external" href="https://docs.python.org/3/reference/datamodel.html?highlight=__slots__#implementing-descriptors"&gt;descriptors&lt;/a&gt;. For our purpose, descriptors are a
way to extend the workings of &lt;tt class="docutils literal"&gt;__getattribute__&lt;/tt&gt; and friends. A
&lt;em&gt;descriptor&lt;/em&gt; is an object whose type implements a &lt;tt class="docutils literal"&gt;__get__&lt;/tt&gt; method,
and when that object is found in a type's dictionary, it is called
instead of checking the &lt;tt class="docutils literal"&gt;__dict__&lt;/tt&gt;. Something like this &lt;a class="footnote-reference" href="https://seecoresoftware.com/blog/2018/08/cpython-vs-pypy-memory-usage.html#f5" id="id8"&gt;[5]&lt;/a&gt;:&lt;/p&gt;
&lt;pre class="code python"&gt;&lt;a name="rest_code_d45069f1cc0542c98355758867c7b60b-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a name="rest_code_d45069f1cc0542c98355758867c7b60b-2"&gt;&lt;/a&gt;
&lt;a name="rest_code_d45069f1cc0542c98355758867c7b60b-3"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__getattribute__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a name="rest_code_d45069f1cc0542c98355758867c7b60b-4"&gt;&lt;/a&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;a name="rest_code_d45069f1cc0542c98355758867c7b60b-5"&gt;&lt;/a&gt;           &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nb"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'__get__'&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
&lt;a name="rest_code_d45069f1cc0542c98355758867c7b60b-6"&gt;&lt;/a&gt;           &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="fm"&gt;__get__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;a name="rest_code_d45069f1cc0542c98355758867c7b60b-7"&gt;&lt;/a&gt;
&lt;a name="rest_code_d45069f1cc0542c98355758867c7b60b-8"&gt;&lt;/a&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__dict__&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a name="rest_code_d45069f1cc0542c98355758867c7b60b-9"&gt;&lt;/a&gt;             &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__dict__&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;a name="rest_code_d45069f1cc0542c98355758867c7b60b-10"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a name="rest_code_d45069f1cc0542c98355758867c7b60b-11"&gt;&lt;/a&gt;
&lt;a name="rest_code_d45069f1cc0542c98355758867c7b60b-12"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__setattr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a name="rest_code_d45069f1cc0542c98355758867c7b60b-13"&gt;&lt;/a&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;a name="rest_code_d45069f1cc0542c98355758867c7b60b-14"&gt;&lt;/a&gt;           &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nb"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'__set__'&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
&lt;a name="rest_code_d45069f1cc0542c98355758867c7b60b-15"&gt;&lt;/a&gt;           &lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="fm"&gt;__set__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;a name="rest_code_d45069f1cc0542c98355758867c7b60b-16"&gt;&lt;/a&gt;           &lt;span class="k"&gt;return&lt;/span&gt;
&lt;a name="rest_code_d45069f1cc0542c98355758867c7b60b-17"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__dict__&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
&lt;/pre&gt;&lt;p&gt;When the &lt;tt class="docutils literal"&gt;class&lt;/tt&gt; statement (indeed, when the &lt;tt class="docutils literal"&gt;type&lt;/tt&gt; metaclass)
finds &lt;tt class="docutils literal"&gt;__slots__&lt;/tt&gt; in the class body (the class dictionary), &lt;a class="reference external" href="https://github.com/python/cpython/blob/2bea7716093012319b5e6a4260fe802b15031f21/Objects/typeobject.c#L2198"&gt;it
takes special steps&lt;/a&gt;. Most importantly, it creates a descriptor for
each mentioned slot and places it in the class's &lt;tt class="docutils literal"&gt;__dict__&lt;/tt&gt;. So our
&lt;tt class="docutils literal"&gt;Point3DSlot&lt;/tt&gt; class gets three such descriptors:&lt;/p&gt;
&lt;pre class="code pycon"&gt;&lt;a name="rest_code_52404834930f448f93ac28ded4530957-1"&gt;&lt;/a&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Point3DSlot&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__dict__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a name="rest_code_52404834930f448f93ac28ded4530957-2"&gt;&lt;/a&gt;&lt;span class="go"&gt;{'__doc__': None,&lt;/span&gt;
&lt;a name="rest_code_52404834930f448f93ac28ded4530957-3"&gt;&lt;/a&gt;&lt;span class="go"&gt;'__init__': &amp;lt;function __main__.__init__&amp;gt;,&lt;/span&gt;
&lt;a name="rest_code_52404834930f448f93ac28ded4530957-4"&gt;&lt;/a&gt;&lt;span class="go"&gt;'__module__': '__main__',&lt;/span&gt;
&lt;a name="rest_code_52404834930f448f93ac28ded4530957-5"&gt;&lt;/a&gt;&lt;span class="go"&gt;'__slots__': ('x', 'y', 'z'),&lt;/span&gt;
&lt;a name="rest_code_52404834930f448f93ac28ded4530957-6"&gt;&lt;/a&gt;&lt;span class="go"&gt;'x': &amp;lt;member 'x' of 'Point3DSlot' objects&amp;gt;,&lt;/span&gt;
&lt;a name="rest_code_52404834930f448f93ac28ded4530957-7"&gt;&lt;/a&gt;&lt;span class="go"&gt;'y': &amp;lt;member 'y' of 'Point3DSlot' objects&amp;gt;,&lt;/span&gt;
&lt;a name="rest_code_52404834930f448f93ac28ded4530957-8"&gt;&lt;/a&gt;&lt;span class="go"&gt;'z': &amp;lt;member 'z' of 'Point3DSlot' objects&amp;gt;}&lt;/span&gt;
&lt;a name="rest_code_52404834930f448f93ac28ded4530957-9"&gt;&lt;/a&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;pds&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;
&lt;a name="rest_code_52404834930f448f93ac28ded4530957-10"&gt;&lt;/a&gt;&lt;span class="go"&gt;1&lt;/span&gt;
&lt;a name="rest_code_52404834930f448f93ac28ded4530957-11"&gt;&lt;/a&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;Point3DSlot&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="fm"&gt;__get__&lt;/span&gt;
&lt;a name="rest_code_52404834930f448f93ac28ded4530957-12"&gt;&lt;/a&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;wrapper&lt;/span&gt; &lt;span class="s1"&gt;'__get__'&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;member_descriptor&lt;/span&gt; &lt;span class="nb"&gt;object&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="mh"&gt;0x10b6fc2d8&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;a name="rest_code_52404834930f448f93ac28ded4530957-13"&gt;&lt;/a&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;Point3DSlot&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="fm"&gt;__get__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Point3DSlot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a name="rest_code_52404834930f448f93ac28ded4530957-14"&gt;&lt;/a&gt;&lt;span class="go"&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;div class="section" id="variable-storage"&gt;
&lt;h4&gt;&lt;a class="toc-backref" href="https://seecoresoftware.com/blog/2018/08/cpython-vs-pypy-memory-usage.html#id14"&gt;Variable Storage&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;We've established &lt;em&gt;how&lt;/em&gt; we can access these magic, hidden slotted
attributes (through the descriptor protocol). (We've also established
why we can't have defaults for slotted attributes in the class.) But
we still haven't found out &lt;em&gt;where&lt;/em&gt; they are stored. If they're not in
a dictionary, where are they?&lt;/p&gt;
&lt;p&gt;The answer is that they're stored directly in the object itself. Every
type has a member called &lt;a class="reference external" href="https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_basicsize"&gt;tp_basicsize&lt;/a&gt;, exposed to Python as
&lt;tt class="docutils literal"&gt;__basicsize__&lt;/tt&gt;. When the interpreter allocates an object, it
allocates &lt;tt class="docutils literal"&gt;__basicsize__&lt;/tt&gt; bytes for it (every object has a minimum
basic size, the size of &lt;tt class="docutils literal"&gt;object&lt;/tt&gt;). The &lt;tt class="docutils literal"&gt;type&lt;/tt&gt; metaclass arranges
for &lt;tt class="docutils literal"&gt;__basicsize__&lt;/tt&gt; to be big enough to hold (a pointer to) each of
the slotted attributes, which are kept in memory immediately after the
data for the basic &lt;tt class="docutils literal"&gt;object&lt;/tt&gt; . The descriptor for each attribute,
then, just does some pointer arithmetic off of &lt;tt class="docutils literal"&gt;self&lt;/tt&gt; to read and
write the value. In a way, it's very similar to how
&lt;a class="reference external" href="https://docs.python.org/3/library/collections.html#collections.namedtuple"&gt;collections.namedtuple&lt;/a&gt; works, except using pointers instead of
indices.&lt;/p&gt;
&lt;p&gt;That may be hard to follow, so here's an example.&lt;/p&gt;
&lt;p&gt;The basic size of &lt;tt class="docutils literal"&gt;object&lt;/tt&gt; exactly matches the reported size of its
instances:&lt;/p&gt;
&lt;pre class="code pycon"&gt;&lt;a name="rest_code_3b89ee9664cb44d39aef7aaf29824d45-1"&gt;&lt;/a&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__basicsize__&lt;/span&gt;
&lt;a name="rest_code_3b89ee9664cb44d39aef7aaf29824d45-2"&gt;&lt;/a&gt;&lt;span class="go"&gt;16&lt;/span&gt;
&lt;a name="rest_code_3b89ee9664cb44d39aef7aaf29824d45-3"&gt;&lt;/a&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getsizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;a name="rest_code_3b89ee9664cb44d39aef7aaf29824d45-4"&gt;&lt;/a&gt;&lt;span class="go"&gt;16&lt;/span&gt;
&lt;/pre&gt;&lt;p&gt;We get the same when we create an object that cannot have any instance
variables, and hence does not need to be tracked by the garbage
collector:&lt;/p&gt;
&lt;pre class="code pycon"&gt;&lt;a name="rest_code_bc429f3cd44a4f40b1378d5a1e376db3-1"&gt;&lt;/a&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NoSlots&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a name="rest_code_bc429f3cd44a4f40b1378d5a1e376db3-2"&gt;&lt;/a&gt;&lt;span class="gp"&gt;... &lt;/span&gt;    &lt;span class="vm"&gt;__slots__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;
&lt;a name="rest_code_bc429f3cd44a4f40b1378d5a1e376db3-3"&gt;&lt;/a&gt;&lt;span class="gp"&gt;...&lt;/span&gt;
&lt;a name="rest_code_bc429f3cd44a4f40b1378d5a1e376db3-4"&gt;&lt;/a&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;NoSlots&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__basicsize__&lt;/span&gt;
&lt;a name="rest_code_bc429f3cd44a4f40b1378d5a1e376db3-5"&gt;&lt;/a&gt;&lt;span class="go"&gt;16&lt;/span&gt;
&lt;a name="rest_code_bc429f3cd44a4f40b1378d5a1e376db3-6"&gt;&lt;/a&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getsizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NoSlots&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;a name="rest_code_bc429f3cd44a4f40b1378d5a1e376db3-7"&gt;&lt;/a&gt;&lt;span class="go"&gt;16&lt;/span&gt;
&lt;/pre&gt;&lt;p&gt;When we add one slot to an object, its basic size increases by one
pointer (8 bytes), and because that object could be tracked by the
garbage collector, &lt;em&gt;this&lt;/em&gt; object needs to be tracked by the collector,
so &lt;tt class="docutils literal"&gt;getsizeof&lt;/tt&gt; reports some extra overhead:&lt;/p&gt;
&lt;pre class="code pycon"&gt;&lt;a name="rest_code_8303f43b487e49eb8fb83627a0c89ab7-1"&gt;&lt;/a&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OneSlot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a name="rest_code_8303f43b487e49eb8fb83627a0c89ab7-2"&gt;&lt;/a&gt;&lt;span class="gp"&gt;... &lt;/span&gt;    &lt;span class="vm"&gt;__slots__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'a'&lt;/span&gt;&lt;span class="p"&gt;,)&lt;/span&gt;
&lt;a name="rest_code_8303f43b487e49eb8fb83627a0c89ab7-3"&gt;&lt;/a&gt;&lt;span class="gp"&gt;...&lt;/span&gt;
&lt;a name="rest_code_8303f43b487e49eb8fb83627a0c89ab7-4"&gt;&lt;/a&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;OneSlot&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__basicsize__&lt;/span&gt;
&lt;a name="rest_code_8303f43b487e49eb8fb83627a0c89ab7-5"&gt;&lt;/a&gt;&lt;span class="go"&gt;24&lt;/span&gt;
&lt;a name="rest_code_8303f43b487e49eb8fb83627a0c89ab7-6"&gt;&lt;/a&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getsizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OneSlot&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;a name="rest_code_8303f43b487e49eb8fb83627a0c89ab7-7"&gt;&lt;/a&gt;&lt;span class="go"&gt;56&lt;/span&gt;
&lt;/pre&gt;&lt;p&gt;The basic size for an object with 3 slots is 16 (the size of &lt;tt class="docutils literal"&gt;object&lt;/tt&gt;) + 3 pointers, or 40.
What's the basic size for an object that has a &lt;tt class="docutils literal"&gt;__dict__&lt;/tt&gt;?&lt;/p&gt;
&lt;pre class="code pycon"&gt;&lt;a name="rest_code_8811138c4f784191b1eb4e84635d7a7f-1"&gt;&lt;/a&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;Point3DSlot&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__basicsize__&lt;/span&gt;
&lt;a name="rest_code_8811138c4f784191b1eb4e84635d7a7f-2"&gt;&lt;/a&gt;&lt;span class="go"&gt;40&lt;/span&gt;
&lt;a name="rest_code_8811138c4f784191b1eb4e84635d7a7f-3"&gt;&lt;/a&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;Point&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__basicsize__&lt;/span&gt;
&lt;a name="rest_code_8811138c4f784191b1eb4e84635d7a7f-4"&gt;&lt;/a&gt;&lt;span class="go"&gt;32&lt;/span&gt;
&lt;/pre&gt;&lt;p&gt;Hmm, it's 16 + &lt;em&gt;2&lt;/em&gt; pointers. What could those two pointers be?
Documentation to the rescue:&lt;/p&gt;
&lt;blockquote&gt;
&lt;tt class="docutils literal"&gt;__slots__&lt;/tt&gt; allow us to explicitly declare data members (like
properties) and deny the creation of &lt;tt class="docutils literal"&gt;__dict__&lt;/tt&gt; and
&lt;tt class="docutils literal"&gt;__weakref__&lt;/tt&gt;  (unless explicitly declared in &lt;tt class="docutils literal"&gt;__slots__&lt;/tt&gt;...)&lt;/blockquote&gt;
&lt;p&gt;So those two pointers are for &lt;tt class="docutils literal"&gt;__dict__&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;__weakref__&lt;/tt&gt;, things
that standard objects get automatically, but which we have to opt-in
to if we want them with &lt;tt class="docutils literal"&gt;__slots__&lt;/tt&gt;. Thus, an object with three
slots is one pointer size bigger than a standard object.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="how-pypy-does-better"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="https://seecoresoftware.com/blog/2018/08/cpython-vs-pypy-memory-usage.html#id15"&gt;How PyPy Does Better&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;By now we should understand why the memory usage dropped significantly
when we added &lt;tt class="docutils literal"&gt;__slots__&lt;/tt&gt; to our objects on CPython (although that
comes with a cost). That leaves the question: how does PyPy get such
good memory performance with a &lt;tt class="docutils literal"&gt;__dict__&lt;/tt&gt; that &lt;tt class="docutils literal"&gt;__slots__&lt;/tt&gt; doesn't
even matter?&lt;/p&gt;
&lt;p&gt;Earlier I wrote that the &lt;tt class="docutils literal"&gt;__dict__&lt;/tt&gt; of an instance is just a
standard dictionary, not specialized at all. That's basically true on
CPython, but it's not at all true on PyPy. PyPy basically fakes
&lt;tt class="docutils literal"&gt;__dict__&lt;/tt&gt; by using &lt;tt class="docutils literal"&gt;__slots__&lt;/tt&gt; for all objects.&lt;/p&gt;
&lt;p&gt;A given set of attributes (such as our "x", "y", "z" attributes for
&lt;tt class="docutils literal"&gt;Point3DSlot&lt;/tt&gt;) is called a "map". Each instance refers to its map,
which tells PyPy how to efficiently access a given attribute. When an
attribute is added or deleted, a new map is created (or re-used from
an existing object; objects of completely unrelated types, but having
common attributes can share the same maps) and assigned to the object,
re-arranging things as needed. It's as if &lt;tt class="docutils literal"&gt;__slots__&lt;/tt&gt; was assigned
to each instance, with descriptors added and removed for the instance
on the fly.&lt;/p&gt;
&lt;p&gt;If the program ever directly accesses an instance's &lt;tt class="docutils literal"&gt;__dict__&lt;/tt&gt;, PyPy
creates a thin wrapper object that operates on the object's map.&lt;/p&gt;
&lt;p&gt;So for a program that has many simalar looking objects, even if
unrelated, PyPy's approach can save a lot of memory. On the other
hand, if the program creates objects that have a very diverse set of
attributes, and that program frequently directly accessess
&lt;tt class="docutils literal"&gt;__dict__&lt;/tt&gt;, it's theoretically possible that PyPy could use &lt;em&gt;more&lt;/em&gt;
memory than CPython.&lt;/p&gt;
&lt;p&gt;You can read more about this approach in &lt;a class="reference external" href="https://morepypy.blogspot.com/2010/11/efficiently-implementing-python-objects.html#using-maps-for-memory-efficient-instances"&gt;this PyPy blog post&lt;/a&gt;.&lt;/p&gt;
&lt;p class="rubric"&gt;Footnotes&lt;/p&gt;
&lt;table class="docutils footnote" frame="void" id="f1" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label"&gt;&lt;col&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="https://seecoresoftware.com/blog/2018/08/cpython-vs-pypy-memory-usage.html#id1"&gt;[1]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;All 64-bit builds, all tested on macOS. The results on Linux
were very similar.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="f2" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label"&gt;&lt;col&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="https://seecoresoftware.com/blog/2018/08/cpython-vs-pypy-memory-usage.html#id4"&gt;[2]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Available at &lt;a class="reference external" href="https://gist.github.com/jamadden/8c1aa567013e2eed546c0a1dff584263"&gt;this gist&lt;/a&gt;.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="f3" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label"&gt;&lt;col&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="https://seecoresoftware.com/blog/2018/08/cpython-vs-pypy-memory-usage.html#id5"&gt;[3]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;In CPython. But I'm getting ahead of myself.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="f4" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label"&gt;&lt;col&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="https://seecoresoftware.com/blog/2018/08/cpython-vs-pypy-memory-usage.html#id7"&gt;[4]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;The CPython dict implementation was &lt;a class="reference external" href="https://docs.python.org/3/whatsnew/3.6.html#whatsnew36-compactdict"&gt;completely overhauled in
CPython 3.6&lt;/a&gt;.
And based on the sizes of &lt;tt class="docutils literal"&gt;{}&lt;/tt&gt; versus &lt;tt class="docutils literal"&gt;pd.__dict__&lt;/tt&gt; we
can see some sort of specialization for instance
dictionaries, at least in terms of their fill factor.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="f5" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label"&gt;&lt;col&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="https://seecoresoftware.com/blog/2018/08/cpython-vs-pypy-memory-usage.html#id8"&gt;[5]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;This is very rough, and actually inaccurate in some small but
important details. Refer to the documentation for the full protocol.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="f6" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label"&gt;&lt;col&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="https://seecoresoftware.com/blog/2018/08/cpython-vs-pypy-memory-usage.html#id2"&gt;[6]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;No, I'm not totally sure why Python 3.7 is such an outlier
and uses more memory than the other Python 3.x versions.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="f7" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label"&gt;&lt;col&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="https://seecoresoftware.com/blog/2018/08/cpython-vs-pypy-memory-usage.html#id3"&gt;[7]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;See &lt;a class="reference external" href="https://docs.python.org/3/c-api/long.html#c.PyLong_FromLong"&gt;PyLong_FromLong&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="f8" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label"&gt;&lt;col&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="https://seecoresoftware.com/blog/2018/08/cpython-vs-pypy-memory-usage.html#id6"&gt;[8]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;With a particular desired &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Hash_table#Key_statistics"&gt;load factor&lt;/a&gt;.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;</description><category>cpython</category><category>memory</category><category>pypy</category><category>python</category><guid>https://seecoresoftware.com/blog/2018/08/cpython-vs-pypy-memory-usage.html</guid><pubDate>Wed, 08 Aug 2018 13:22:07 GMT</pubDate></item></channel></rss>