Deep Dive
low level designdesign patternsoop

Flyweight: One 'e' for a Million Letters

When you must hold millions of near-identical objects, one-object-per-instance quietly blows the heap. Flyweight splits shared shape from per-use position — and hands out one copy for all of them.

·14 min read
Medium

A code editor holds a document. The document holds characters. So — naively — a 2 MB source file is two million Character objects, each with a font reference, a style, a colour, a glyph outline. On a 64-bit JVM, an object header alone is 16 bytes; add a few fields and each character costs ~50 bytes. Two million of them is 100 MB of heap for a file that is 2 MB on disk. Open five tabs and the editor is swapping.

Here is the thing the naive model misses: those two million characters are drawn from an alphabet of maybe eighty distinct glyphs. Every 'e' in the file has the same shape, the same outline, the same metrics. The only thing that differs between one 'e' and the next is where it sits and what colour it is. You are storing the expensive, identical part two million times to carry the cheap, unique part.

The intuition: the print shop’s letter stamp

A letterpress print shop does not cast a fresh metal 'e' for every 'e' on the page. It owns one stamp per letter. To print a word, the compositor arranges the same physical stamps into a frame, inks them, and presses. The stamp carries the letter’s shape — that never changes. The frame’s layout carries the position — that changes every line.

The stamp is the flyweight: shared, immutable, expensive to make, reused everywhere. The position in the frame is supplied fresh each time. A print shop with a hundred stamps can typeset an entire book, because the book is not a hundred million pieces of metal — it is a hundred pieces of metal, arranged a hundred million times.

From here the members-only continuation builds the pattern end to end: the factory-and-pool structure with a diagram, the runnable Glyph/GlyphFactory code, the O(N)→O(K) memory arithmetic, the JDK flyweights hiding in Integer.valueOf and the string pool, the gains-vs-costs tradeoffs, and an interview corner where you cut a million map markers from 40 GB down to a few dozen icons.

Members only

Keep reading with Premium

You've reached the members-only part of this deep-dive — the full implementation, the interactive ring simulator, and the step-by-step walkthrough. Unlock it with a membership.

Related Articles