When Python Runs Out of Memory

If a Python step stops with a message about the device running out of memory, nothing is broken and you have not written bad code. You have hit a real ceiling, and there are two ways past it: make the work smaller, or move it somewhere with more room.

What actually happened

Python can run in two places, and they have different limits.

Where it ranWhat it isMemory
On this deviceThe phone, tablet or computer you are working on. The default — nothing to connect, nothing to install.Bounded, and smaller on a phone than on a laptop
Through CircuitA computer of your own, running the Python it has installed.Your computer's own memory

Running on this device is deliberately self-contained, and the trade for that is a fixed amount of memory to work in. When a step asks for more than is there, the run stops outright rather than raising an ordinary Python error. That is why there is no traceback and no line number to look at — the work ended before Python could report anything.

So the absence of a traceback is not missing information. It is the signal.

The two routes

Think of it as choosing per step, not once for everything:

  • On this device — ordinary work. Reading and reshaping data, charts, most numeric passes, anything you are exploring or teaching. It needs nothing connected and it works offline.
  • Through Circuit — when you need speed and power. Large data, big images, long numeric runs, anything that has already hit the ceiling once. Your own machine runs the same code with its own memory and, typically, a good deal faster.

Neither is the "real" one. Most notebooks never need the second, and reaching for it early costs you the thing that makes the first pleasant — that it just runs, anywhere, with nothing set up.

Making it fit on this device

Memory goes on the things you build, not on the length of your code. In rough order of how often each one is the culprit:

Plot settings, not plot data

This is the most common surprise. A chart's own detail settings usually cost far more than the numbers behind them, because every facet, marker or sample becomes an object to draw.

On a 3D surface, raising the detail setting took the same plot from about 70 MB to about 125 MB — enough to stop it on a phone — for a difference that was invisible at the size it was being viewed. If a plotting step is what died, look at its resolution, sample count and figure settings before you touch the data.

Grid and array size

An array's cost is every dimension multiplied together. Doubling the resolution of a two-dimensional grid does not double the memory — it quadruples it. Going from a 200-point grid to a 400-point one turns 40,000 values into 160,000.

Halving a grid you are only looking at is usually free in every way that matters.

The width of each number

By default each number takes eight bytes. Halve that with float32 when you do not need the precision:

Z = np.sin(np.sqrt(X ** 2 + Y ** 2)).astype("float32")

For anything you are plotting rather than accumulating, the difference is invisible in the result and immediate in the memory.

Copies you did not ask for

Each intermediate expression makes a new array. A chain like (a + b) * c - d holds several full-size copies at once, even though you only wanted the last one. Where an array is large, work in place:

a += b      # instead of a = a + b
a *= c      # instead of a = a * c

And let go of what you have finished with, especially in a notebook, where every cell's variables stay alive until you clear them:

del big_intermediate

Loops that accumulate

Appending to a list inside a long loop grows without limit and builds a separate Python object for every element. Where the work is numeric, doing it to the whole array at once is both far faster and far smaller.

Images

Load, resize, then process — not the other way round. A photograph straight off a phone camera is many times larger in memory than it is on disk, and most image work does not need the full resolution.

One cell at a time

In a notebook, everything every cell has made is still in memory. If you have been iterating for a while, re-running from a clean state often fixes a step that has started failing — nothing in that step changed, it simply ran out of room left by everything above it.

Moving it to your computer

When the work genuinely needs the room, connect Circuit and pick that computer in the step's settings. The same code runs unchanged — this is a change of where, not a change of what you wrote.

This is also the answer when the honest verdict is that the work does not fit. Some jobs are simply bigger than a phone, and shrinking them past a point means doing different work rather than the same work more carefully.