Language runtime basics
Memory, stack vs heap, garbage collection, async I/O, threads, and processes.
Frameworks hide the runtime until something gets slow, stuck, or memory-hungry. Knowing how code actually runs helps you debug performance and choose safer architecture.
The big idea
Your code runs inside a runtime that manages memory, schedules work, talks to the OS, and decides how concurrency happens.
handlers, services, jobs
VM, GC, event loop, thread pool
memory, files, sockets, signals
CPU scheduling, network, disk
When production is slow, the bug may be in any of those layers.
Stack and heap
- Stack
- Function calls and short-lived local state. Fast, structured, limited.
- Heap
- Objects that outlive one call frame. Flexible, garbage-collected or manually managed.
- Pointer/reference
- A small value that points at data somewhere else.
- Garbage collection
- Runtime cleanup of unreachable heap objects.
Memory leaks in garbage-collected languages still happen: a cache, global list, closure, or listener can keep references alive forever.
Processes, threads, and async
| Attribute | What it is | Trade-off |
|---|---|---|
| Process | Own memory space | Strong isolation, heavier startup |
| Thread | Shares process memory | Cheap sharing, synchronization risk |
| Coroutine/task | Runtime-scheduled work | Great for I/O, not magic CPU parallelism |
| Event loop | One loop dispatches callbacks | Blocked by long CPU work |
Async code helps when waiting on network, disk, or timers. It does not make CPU-heavy code free. A single blocking loop can freeze an event-loop service.
Common runtime failures
- High CPU
- Hot loop, expensive serialization, compression, crypto, or too much concurrency.
- High memory
- Unbounded cache, large response, leaked listeners, or data loaded all at once.
- Stuck requests
- Thread pool exhaustion, blocked event loop, missing timeout, or deadlock.
- Slow startup
- Heavy imports, migrations at boot, cold caches, or synchronous network calls.
What to inspect
top
ps -o pid,ppid,%cpu,%mem,cmd -p <pid>
lsof -p <pid>
curl -w '%{time_total}\n' -o /dev/null -s http://localhost:3000/In language-specific tools, learn the profiler, heap snapshot, thread dump, or event-loop delay monitor for the runtime you use most.
Runtime-specific instincts
- Node.js: avoid long CPU work on the event loop; watch event-loop delay.
- Python: understand the GIL; use async for I/O and workers/processes for CPU.
- Java/JVM: watch heap size, GC pauses, thread pools, and warmup.
- Go: goroutines are cheap, but leaks and unbounded channels still hurt.
In practice
Write a tiny endpoint that sleeps, another that loops CPU for two seconds, and another that allocates a large array. Hit each with concurrent requests. Watch how the runtime behaves. This is more memorable than a page of definitions.
Key takeaways
- The runtime schedules work, manages memory, and turns code into OS activity.
- Garbage collection prevents many manual frees, but not leaked references.
- Async helps I/O waits; CPU-heavy code still needs separate capacity.
- Threads, processes, event loops, and coroutines fail in different ways.
- Learn one profiler or runtime inspection tool before you need it in an outage.
Checkpoint questions
Use these to test whether the lesson is clear enough to explain without rereading.
- 1What lives on the stack, what lives on the heap, and why does that matter?
- 2How do threads, processes, coroutines, and event loops differ?
- 3What can block an async service even when the code uses async syntax?
- 4Which runtime behavior would you inspect for high memory, high CPU, or stuck requests?
References
External resources for going deeper after the lesson above.