All Articles

C++ for JavaScript Devs: Understanding Memory Management Without Panicking

Pointers sound terrifying until someone explains them in plain English. A web developer's guide to the C++ concepts that actually matter — without the computer science textbook.

You've been writing JavaScript for years. Arrays, objects, functions — you understand these. You decide to try Arduino for a side project. You open a C++ tutorial. Within two minutes you're reading about pointers, heap allocation, and manual memory management, and you close the tab.

This happens constantly, and it's a shame. Because once someone explains what these concepts actually mean — using the knowledge you already have — the panic evaporates.

This is that explanation.


First: The Biggest Mindset Shift

In JavaScript, you never think about where your data lives in memory. You create an array:

const scores = [10, 25, 42, 7];

And it exists. Somewhere. You don't know where, and you don't have to care. When you're done with it, JavaScript's garbage collector notices nobody is using scores anymore and frees up the memory automatically. This is enormously convenient and costs you nothing — except that it removes a layer of control.

In C++ (and on an Arduino), there is no garbage collector. The computer won't clean up after you. You are responsible for managing memory, which means you need to understand what memory is and how data sits inside it.

That's the shift: from "the runtime manages memory for me" to "I manage memory myself."


Arrays: The First Difference

In JavaScript, arrays are magical rubber-band containers. They hold anything, grow automatically, and don't care about types:

const stuff = [1, "hello", true, { id: 42 }];
stuff.push("another thing"); // grows automatically

In C++, an array is a fixed-size block of identically-typed slots:

int scores[4] = {10, 25, 42, 7};
// scores holds exactly 4 integers. That's it.
// scores[4] = 99; ← this writes past the end of the array. Chaos ensues.

The C++ array doesn't know its own length. It's just 4 consecutive boxes in memory, each holding an int. If you go past the end, you're writing into memory that belongs to something else. This is called a buffer overflow, and it's both a common bug and a famous security vulnerability.

On an Arduino, this matters even more because you have 2KB of RAM. That's not a typo. 2,048 bytes. A JavaScript runtime wouldn't even fit in that space. Every byte is precious.


What Is a Pointer? (Really.)

A pointer is just a variable that stores a memory address instead of a value.

Here's the analogy: imagine your computer's RAM is a street of numbered houses. Each house has an address (like house number 1042) and a resident (the actual data). A pointer is a sticky note that says "the data you want lives at house 1042."

In JavaScript terms: every object and array you create is a "house," and when you assign an object to a variable, that variable is secretly holding the address, not the object itself. You've been using pointers for years. You just didn't see the address.

const a = { value: 10 };
const b = a; // b points to the SAME object
b.value = 99;
console.log(a.value); // 99 — because a and b are the same house

In C++, this is just made explicit:

int x = 10;          // x is a house, its value is 10
int* p = &x;         // p is a sticky note pointing to x's address
                     // & means "give me the address of"
 
*p = 99;             // *p means "go to the house p points to"
                     // now x is 99

The * and & operators are the only new pieces. Everything else is logic you already know.


The Stack vs the Heap

Here's where memory management gets real. C++ has two places to put data:

The Stack — fast, automatic, temporary. When you declare a variable inside a function, it goes on the stack. When the function returns, the stack clears automatically. No cleanup needed.

void doSomething() {
    int count = 0;     // stack: automatically freed when function ends
    count++;
}

The Heap — slower, manual, persists until you free it. When you new something, it goes on the heap. It stays there until you explicitly delete it.

int* score = new int(42);  // allocate on the heap
*score = 100;
delete score;              // YOU must free this or it leaks

In JavaScript, all your objects go on the equivalent of the heap, and the garbage collector calls delete for you when it detects nobody references the object anymore. That's literally it. That's the whole job of a garbage collector.

On an Arduino, heap allocation exists but is discouraged. With only 2KB of RAM, heap fragmentation — lots of small allocations leaving unusable gaps — can crash your sketch hours after it seemed to be working fine. Arduino best practice is to keep almost everything on the stack or in global variables.


Why Arduino Can't Garbage Collect

Garbage collectors are not magic — they're programs that run alongside your code, periodically scanning memory, finding unreachable objects, and freeing them. This requires:

  • A runtime environment to host the collector
  • CPU cycles to run scans
  • Memory to track what's alive and what isn't

An Arduino Uno has an 8-bit processor running at 16MHz and 2KB of RAM. There's no room for a runtime. There's barely room for your actual program. The microcontroller executes your compiled binary directly, instruction by instruction, with nothing between your code and the hardware.

This is also why Arduino code is so fast for what it is. There's no runtime overhead, no JIT compilation, no garbage collection pauses. What you write is (almost) what runs.

The tradeoff is that you need to be careful:

// BAD on Arduino: repeated heap allocation in a loop
void loop() {
    char* buffer = new char[64];  // allocates every iteration
    // ... use buffer ...
    delete[] buffer;              // if you forget this once, leak
}
 
// GOOD on Arduino: static allocation
char buffer[64];  // declared once, lives forever
 
void loop() {
    // ... use buffer ...
}

A Rosetta Stone: Side by Side

ConceptJavaScriptC++
Dynamic arrayconst arr = [1,2,3]std::vector<int> arr = {1,2,3}
Fixed arrayN/A (sort of)int arr[3] = {1,2,3}
Get variable's addressImplicit (hidden)&myVar
Pointer variableImplicit referenceint* ptr = &myVar
Dereference (get value at address)Automatic*ptr
Allocate on heapnew Object()new int(42)
Free heap memoryAutomatic (GC)delete ptr
Type safetyRuntime / TypeScriptCompile-time, strict

Where to Go From Here

Once the mental model clicks, the actual Arduino/C++ learning path is not that long:

  1. Read the Arduino documentation — it's specifically written for non-C++ developers and avoids most of the dangerous memory patterns
  2. Start with stack variables only — avoid new entirely until you understand the stack deeply
  3. Use Serial.println() to debug — it's your console.log
  4. Learn struct — it's like a JavaScript object with explicit types, and it's how you organize data on embedded systems

The jump from web dev to hardware dev is smaller than it looks. The concepts aren't new — they're just lower-level versions of things you already understand. C++ is JavaScript with the hood open.

And once you've written code that physically moves something in the real world because of your logic, the 2KB RAM constraint suddenly seems like a fair trade.

Share
Enjoyed this article?

Check out what I've built

From Roblox games with millions of visits to open-source developer tools — see everything on my portfolio.

View Portfolio