Top 50 Operating System Interview Questions and Answers (2026)
Operating system questions are not just for kernel engineers. They are how interviewers find out whether you understand what your code is actually doing when it runs: why a thread pool helps, why a lock can hang a service, why a container got killed, why a machine with idle CPUs has a load average of 40. New-grad loops ask them directly; backend, SRE, platform and embedded loops ask them disguised as production stories.
The 50 questions below escalate the way a real round does: fundamentals, processes and threads, scheduling, synchronization and deadlock, memory management, file systems and I/O, then virtualization and containers. After the 50 there is a bonus part of production scenarios (questions 51-56) and a quick-fire round.
Practice alongside this post. The same ground is drilled as timed multiple-choice in the operating systems question bank (43 graded questions, from context-switch overhead to journaling); the Bash & Linux question bank covers the command-line side. Keep the concurrency essentials cheat sheet open for Part 4 and the Linux performance essentials cheat sheet for the scenarios, and the free daily challenge gives you one question a day with no account needed.
Part 1: Fundamentals (1-8)
1. What does an operating system actually do?
It manages hardware on behalf of programs and protects programs from each other. Concretely: it schedules processes and threads onto CPUs, gives each process its own virtual address space, mediates access to devices and files, enforces permissions, and provides a stable interface (system calls) so programs do not talk to hardware directly. The short version interviewers like: an OS is a resource manager and an abstraction layer.
2. What is the difference between user mode and kernel mode?
The CPU runs in different privilege levels. In kernel mode, code can execute privileged instructions, touch any memory and talk to devices. In user mode, it cannot; an attempt to do something privileged causes a fault. Applications run in user mode and the kernel runs in kernel mode, which is what stops a buggy program from overwriting another process's memory or taking over the disk controller.
3. What is a system call, and what happens during one?
A system call is how a user-mode program asks the kernel to do something privileged: read, write, open, fork, mmap. The program puts the syscall number and arguments in registers and executes a special instruction (syscall on x86-64). The CPU switches to kernel mode and jumps to the kernel's entry point, the kernel validates the arguments and does the work, then returns to user mode with a result. Syscalls are much more expensive than function calls, which is why buffered I/O batches small writes into fewer write calls. strace shows every syscall a process makes.
4. Monolithic kernel vs microkernel?
A monolithic kernel (Linux, most BSDs) runs the core services (scheduling, memory management, file systems, drivers, networking) in kernel space in one address space. It is fast because components call each other directly, but a driver bug can crash the whole system. A microkernel (seL4, QNX) keeps only the minimum in kernel space (address spaces, scheduling, IPC) and runs drivers and file systems as user-space services. It is more isolated and easier to verify, at the cost of extra IPC. Linux narrows the gap with loadable modules; macOS's XNU is a hybrid.
5. What is the difference between an interrupt, a trap and an exception?
- An interrupt is asynchronous and comes from hardware: a timer tick, a network card saying a packet arrived, a disk finishing a read.
- A trap is synchronous and deliberate: the program asks for the kernel, as in a system call or a breakpoint.
- An exception (or fault) is synchronous and caused by the instruction itself: divide by zero, an invalid memory access, a page fault.
All three transfer control to a kernel handler. The timer interrupt is what makes preemptive scheduling possible: it lets the kernel take the CPU back from a process that never yields.
6. What is a process, and what does the kernel keep about it?
A process is a program in execution: its code, its address space (text, data, heap, stack), and its state. The kernel tracks each one in a process control block (in Linux, task_struct): PID, state, saved registers and program counter, scheduling information, memory mappings, open file descriptors, credentials, signal handlers and accounting.
7. What are the states a process moves through?
New, ready (runnable, waiting for a CPU), running, blocked or waiting (for I/O, a lock, a timer), and terminated. A running process moves to ready when it is preempted, to blocked when it waits for something, and back to ready when the event happens. Linux's ps shows R (running or runnable), S (interruptible sleep), D (uninterruptible sleep, usually disk I/O), T (stopped) and Z (zombie).
8. What happens when a computer boots?
Firmware (UEFI or legacy BIOS) initialises hardware and loads a boot loader (GRUB, systemd-boot). The boot loader loads the kernel and an initial RAM file system into memory and jumps to the kernel. The kernel initialises memory management, drivers and the scheduler, mounts the real root file system, and starts the first user-space process, PID 1 (systemd or init on Linux), which starts everything else.
Part 2: Processes and Threads (9-16)
9. Process vs thread?
A process has its own address space and resources; processes are isolated from each other. A thread is a unit of execution inside a process: threads share the process's memory, heap, open files and code, but each has its own stack, registers and program counter.
Trade-offs: threads are cheaper to create and to switch between and can share data directly, but shared memory means races (Part 4), and one thread corrupting memory or crashing can take down the whole process. Processes give isolation (a crash stays contained) at the cost of heavier creation and explicit IPC. Browsers run each site in separate processes for exactly that isolation.
10. What do fork() and exec() do?
fork() creates a new process that is a copy of the caller. It returns twice: the child's PID in the parent and 0 in the child. exec() (the execve family) replaces the current process's program with a new one, keeping the PID and open file descriptors. A shell runs a command by forking, then calling exec in the child, while the parent waits.
The follow-up: forking a process with gigabytes of memory is fast because of copy-on-write. Parent and child share the same physical pages, marked read-only, and a page is only copied when one of them writes to it.
11. What is a zombie process? An orphan?
A zombie has exited but its parent has not yet collected its exit status with wait(). Its resources are freed but its process table entry remains. A few are harmless; thousands mean a parent that never reaps its children, and they can exhaust the PID space. Fix the parent (handle SIGCHLD and call wait); you cannot kill a zombie because it is already dead.
An orphan is a running process whose parent exited. It is re-parented to PID 1 (or a designated subreaper), which reaps it when it exits. This is why containers need a PID 1 that reaps children, or a small init like tini.
12. What is a context switch, and why is it expensive?
The kernel saves the running thread's registers and program counter, picks another thread, and restores that thread's state. A switch between threads of the same process keeps the address space; a switch between processes also changes the page table base, which can invalidate TLB entries (question 33).
The direct cost is small (microseconds or less). The indirect cost is the bigger one: the new thread finds caches and the TLB full of someone else's data and runs slowly until they warm up. That is why thousands of runnable threads perform worse than a pool sized to the cores, and why event loops and async I/O exist.
13. User-level threads vs kernel threads?
Kernel threads are scheduled by the OS: they can run in parallel on multiple cores and one blocking does not block the others. User-level threads (green threads, coroutines, fibers) are scheduled by a runtime inside one process: very cheap to create and switch, but the kernel only sees the threads they run on.
Mappings: 1:1 (each user thread is a kernel thread: Linux pthreads, traditional Java threads), N:1 (many user threads on one kernel thread: no parallelism), M:N (many user threads multiplexed over a pool of kernel threads: Go goroutines, Java virtual threads). M:N runtimes must avoid letting a blocking syscall stall a whole kernel thread, which is why they integrate with non-blocking I/O.
14. What inter-process communication mechanisms do you know?
- Pipes: a one-way byte stream between related processes (
ls | grep). Named pipes (FIFOs) work between unrelated ones.
- Sockets: Unix domain sockets on one machine, TCP/UDP across machines. Bidirectional and general.
- Shared memory: the fastest, because no data is copied, but you must synchronise access yourself.
- Message queues: kernel-managed queues of discrete messages.
- Signals: tiny asynchronous notifications with no payload beyond the signal number.
- Memory-mapped files and plain files, for larger data.
The trade-off is speed vs safety and convenience: shared memory is fastest and easiest to get wrong; sockets are slower but work across machines.
15. What is a signal? SIGTERM vs SIGKILL?
A signal is an asynchronous notification delivered to a process, which can run a handler, use the default action, or ignore it. SIGTERM (15) asks a process to terminate; it can be caught, so a well-written service finishes in-flight work and exits cleanly. SIGKILL (9) cannot be caught, blocked or ignored; the kernel ends the process immediately with no cleanup. SIGSTOP cannot be caught either. Orchestrators send SIGTERM, wait a grace period, then SIGKILL, which is why your shutdown handler has to finish inside that grace period.
16. Concurrency vs parallelism? Async vs parallel?
Concurrency is structuring a program so several tasks make progress in overlapping time periods; parallelism is actually executing several at the same instant on multiple cores. A single-core machine can be concurrent but not parallel.
Async I/O is a concurrency technique: one thread starts many I/O operations and handles each when it completes, instead of blocking. It helps I/O-bound work (many network calls) and does nothing for CPU-bound work, which needs parallelism (more cores, more threads or processes). Saying which one a workload needs is the point of the question.
Part 3: CPU Scheduling (17-22)
17. Compare the classic scheduling algorithms.
- First-come, first-served (FCFS): simple, but a long job at the front makes everything behind it wait (the convoy effect).
- Shortest job first (SJF): run the shortest burst next. Minimises average waiting time, but needs burst lengths you usually do not know, and long jobs can starve. Its preemptive version is shortest remaining time first.
- Round robin (RR): each runnable job gets a time slice (quantum) in turn. Fair and responsive; too small a quantum wastes time on context switches, too large turns into FCFS.
- Priority scheduling: highest priority runs first; risks starvation of low priorities.
- Multilevel feedback queue (MLFQ): several queues of different priorities; jobs that use their whole slice drop down, jobs that block quickly (interactive ones) stay high. Approximates SJF without knowing burst lengths.
18. Which algorithm minimises average waiting time, and why?
Shortest job first (and shortest remaining time first, if preemption is allowed). Running a short job before a long one makes the short job wait less and the long job wait only slightly longer, so every swap that puts a shorter job first lowers the total. The catch is practical: the scheduler does not know burst lengths in advance, so real systems estimate them from history or approximate with MLFQ.
19. Preemptive vs cooperative scheduling?
In preemptive scheduling the kernel can take the CPU away from a running thread, typically on a timer interrupt or when a higher-priority thread becomes runnable. In cooperative scheduling a thread runs until it voluntarily yields or blocks. Every general-purpose OS kernel is preemptive. Cooperative scheduling survives inside runtimes: a JavaScript event loop or an async framework runs each callback to completion, which is why one CPU-heavy callback freezes everything else.
20. What are starvation and aging?
Starvation is a runnable task never getting the CPU because higher-priority or shorter work keeps arriving. Aging fixes it by gradually raising the priority of tasks that have waited a long time, so they eventually run.
21. What is priority inversion, and how is it solved?
A high-priority task waits for a lock held by a low-priority task, and a medium-priority task preempts the low one, so the high-priority task is effectively blocked by the medium one. The famous example is the Mars Pathfinder lander, which kept resetting until engineers enabled priority inheritance remotely.
Fixes: priority inheritance (the lock holder temporarily inherits the priority of the highest task waiting on it) and priority ceiling (a task holding a lock runs at the highest priority of any task that can take it).
22. How does the Linux scheduler work today?
For normal tasks, Linux used the Completely Fair Scheduler (CFS) from 2.6.23: each task accumulates virtual runtime weighted by its nice value, and the scheduler runs the task with the least virtual runtime, kept in a red-black tree. Since kernel 6.6 the default is EEVDF (earliest eligible virtual deadline first), which keeps the fairness idea but also considers latency by giving each task a virtual deadline. Real-time policies (SCHED_FIFO, SCHED_RR) sit above both and always run first. For an interview, "fair share by weighted virtual runtime, with real-time classes on top" is the core of the answer.
Part 4: Synchronization and Deadlock (23-31)
23. What is a race condition, and what is a critical section?
A race condition is when the result depends on the timing of threads accessing shared data. The classic example is count++ from two threads: it is a read, an increment and a write, and two threads can both read 5 and both write 6. A critical section is the code that touches the shared data and must not be executed by more than one thread at a time. Fix it with mutual exclusion (a lock), an atomic operation, or by not sharing the data at all.
24. Mutex vs semaphore?
A mutex provides mutual exclusion: one holder at a time, and only the thread that locked it should unlock it (ownership). A semaphore is a counter with two atomic operations: wait (decrement, block if zero) and signal (increment, wake a waiter). A counting semaphore limits access to N identical resources, such as a pool of 10 connections. A binary semaphore looks like a mutex but has no ownership: any thread can signal it, which makes it suitable for signalling between threads and unsuitable as a lock (no priority inheritance, no protection against unlocking someone else's lock).
25. Spinlock vs mutex?
A spinlock busy-waits in a loop until the lock is free; a mutex puts the waiting thread to sleep and lets the scheduler run something else. Spinning wastes CPU but avoids the cost of sleeping and waking, so spinlocks only make sense when the critical section is very short and the holder is running on another core, which is why they are common inside kernels. In user space, most mutex implementations spin briefly and then sleep.
26. What is a condition variable, and why must you wait in a loop?
A condition variable lets a thread sleep until some condition about shared state becomes true, releasing the associated mutex while it sleeps and re-acquiring it before it returns. You must re-check the condition in a while loop because of spurious wakeups (the wait can return without a signal) and because another thread may have changed the state between the signal and your wakeup:
pthread_mutex_lock(&m);
while (queue_empty(&q))
pthread_cond_wait(&cv, &m);
item = dequeue(&q);
pthread_mutex_unlock(&m);
Using if instead of while is the bug interviewers are looking for.
27. What are the four conditions for deadlock?
The Coffman conditions, all of which must hold:
- Mutual exclusion: a resource can be held by only one thread.
- Hold and wait: a thread holds one resource while waiting for another.
- No preemption: a resource cannot be taken away; it is only released voluntarily.
- Circular wait: a cycle of threads, each waiting for a resource the next one holds.
Break any one and deadlock is impossible.
28. How do you prevent, avoid and detect deadlock?
- Prevention breaks one condition by design. The practical one is lock ordering: every thread acquires locks in the same global order, so a cycle cannot form. Others: acquire all locks at once (breaks hold and wait), or use
trylock and back off (breaks no-preemption).
- Avoidance checks each request against what could happen and only grants safe ones. The Banker's algorithm is the textbook example; it requires knowing maximum needs in advance, so it is rare outside of textbooks.
- Detection and recovery lets deadlocks happen, finds cycles in a wait-for graph and breaks them by aborting or rolling back a participant. Databases do exactly this: they detect a lock cycle and abort one transaction.
29. Livelock vs starvation vs deadlock?
In a deadlock threads are blocked forever, waiting on each other. In a livelock threads keep running and changing state in response to each other but make no progress, like two people stepping aside in a corridor in the same direction repeatedly; backing off with randomness usually fixes it. Starvation is one thread never getting a resource while others do.
30. What is compare-and-swap, and what is the ABA problem?
Compare-and-swap (CAS) is an atomic instruction: "if this location still holds A, replace it with B, and tell me whether it worked." Lock-free data structures loop on CAS: read the value, compute the new one, CAS, retry on failure.
The ABA problem: a thread reads A, is paused, another thread changes the value to B and back to A, and the first thread's CAS succeeds even though the structure changed underneath it (in a lock-free stack, a node may have been freed and reused). Fixes: a version counter alongside the pointer, or safe memory reclamation schemes like hazard pointers.
31. Solve the bounded-buffer (producer-consumer) problem.
Use a mutex for the buffer and two counting semaphores: empty starts at the buffer size, full at zero.
producer: consumer:
wait(empty) wait(full)
lock(mutex) lock(mutex)
put item take item
unlock(mutex) unlock(mutex)
signal(full) signal(empty)
The order matters: waiting on a semaphore while holding the mutex can deadlock, because the other side needs the mutex to signal. In application code you would use a ready-made blocking queue; the interviewer wants to see that you understand why it works.
Part 5: Memory Management (32-41)
32. What is virtual memory, and why do we use it?
Every process sees its own private, contiguous address space; the hardware (the MMU) and the kernel translate those virtual addresses to physical memory. Benefits:
- Isolation: a process cannot address another process's memory.
- Simplicity: each program is linked as if it owns the whole address space.
- Overcommit and demand paging: memory is only backed by RAM when touched, and rarely used pages can be moved to disk.
- Sharing: shared libraries and copy-on-write pages are mapped into many processes once.
- Memory-mapped files: files can be accessed as memory.
33. How does paging work, and what is the TLB?
Memory is divided into fixed-size pages (commonly 4 KB) and physical memory into frames of the same size. A page table maps virtual page numbers to physical frames, with permission bits. On 64-bit systems page tables are multi-level (four or five levels on x86-64) so that unused regions cost nothing.
Walking several levels on every memory access would be slow, so the CPU caches recent translations in the translation lookaside buffer (TLB). A TLB miss costs a page walk. Huge pages (2 MB or 1 GB) cover more memory per TLB entry, which is why databases and JVMs often use them.
34. What happens on a page fault?
The MMU cannot translate an address (the page is not present, or the access violates permissions) and traps into the kernel. The kernel decides:
- Invalid access (no mapping, or writing to read-only memory): deliver
SIGSEGV.
- Minor fault: the page is in memory but not mapped for this process (for example a shared library page already cached, or a fresh anonymous page to zero-fill). Map it and resume.
- Major fault: the page must be read from disk (swap or a mapped file). Block the process, do the I/O, update the page table, resume.
- Copy-on-write fault: a write to a shared COW page. Copy it, map the copy writable, resume.
The instruction that faulted is restarted, so the program never notices, except in latency.
35. Paging vs segmentation?
Paging splits memory into fixed-size pages: no external fragmentation, simple allocation, but some internal fragmentation in the last page. Segmentation splits it into variable-sized logical segments (code, data, stack) with a base and limit each: matches the program's structure, but suffers external fragmentation. Modern x86-64 systems use paging and keep segmentation only in a vestigial form.
36. What are the common page replacement algorithms?
When memory is full and a page must be evicted:
- Optimal (Belady's): evict the page that will not be used for the longest time. Impossible in practice; useful as a benchmark.
- FIFO: evict the oldest page. Simple and poor, and it suffers Belady's anomaly: more frames can cause more faults.
- LRU: evict the least recently used page. Good, but exact LRU is too expensive to track on every access.
- Clock (second chance): an LRU approximation using the hardware's referenced bit: sweep the pages in a circle, clear the bit if set, evict the first page whose bit is already clear.
Linux uses active and inactive lists (with a newer multi-generational LRU option), a refinement of the same idea.
37. What is thrashing?
The system spends most of its time moving pages between RAM and disk instead of doing work, because the combined working sets of the running processes do not fit in memory. Each process faults, evicts a page another process needs, which then faults, and so on. CPU utilisation falls while disk I/O saturates. Fixes: reduce the number of processes or their memory, add RAM, or let the OOM killer or an admission policy reduce the load. Adding more processes makes it worse.
38. Internal vs external fragmentation?
Internal fragmentation is wasted space inside an allocated block: asking for 5 KB and getting two 4 KB pages wastes 3 KB. External fragmentation is free memory split into pieces too small to satisfy a request, even though the total free space would be enough. Fixed-size allocation (paging, slab allocators) avoids external fragmentation at the cost of some internal; variable-size allocation does the reverse. Compaction fixes external fragmentation but requires moving memory.
39. Stack vs heap?
The stack holds function call frames: local variables, return addresses, saved registers. Allocation is just moving a pointer, it is freed automatically on return, and each thread has its own, of limited size (a deep recursion overflows it). The heap holds dynamically allocated memory whose lifetime is not tied to a function call: allocation goes through an allocator (malloc, new, a garbage collector), is slower, can fragment, and is shared by all threads of the process.
40. What is a memory-mapped file, and when would you use one?
mmap maps a file into the process's address space, so reading or writing memory reads or writes the file through the page cache, with pages loaded on demand by page faults. Advantages: no explicit read calls or extra copies, random access is just pointer arithmetic, and several processes can share one mapping. Used by databases, by the dynamic loader for shared libraries, and for large read-mostly files. The caveats: I/O errors arrive as signals (SIGBUS) instead of return codes, and you still need msync or fsync for durability.
41. What is the OOM killer?
Linux overcommits memory by default: it lets processes allocate more virtual memory than exists, betting they will not touch it all. When physical memory and swap actually run out, the out-of-memory killer picks a process (scored mostly by memory use, adjustable with oom_score_adj) and sends it SIGKILL. In containers, the cgroup memory limit triggers the same thing inside the container. You find it in dmesg or the journal ("Out of memory: Killed process"), and the victim exits with status 137 (question 52).
Part 6: File Systems and I/O (42-47)
42. What is an inode?
On Unix file systems, an inode stores a file's metadata: type, permissions, owner, size, timestamps, link count, and pointers to the data blocks. It does not store the file name. Names live in directories, which map names to inode numbers. That is why a file can have several names (hard links), why renaming within a file system is cheap, and why a disk can report "no space left" while df shows free blocks: it can run out of inodes (df -i).
43. Hard link vs symbolic link?
A hard link is another directory entry pointing at the same inode. All hard links are equal; the data is freed when the last one is removed and no process has the file open. Hard links cannot cross file systems or (normally) point to directories. A symbolic link is a small file containing a path. It can point anywhere, including other file systems and directories, and it breaks (dangles) if the target is moved or deleted.
44. What problem does journaling solve?
Updating a file touches several structures (the inode, the free-block bitmap, the directory, the data). A crash in the middle can leave them inconsistent, which used to mean a long fsck at boot. A journaling file system first writes a description of the change to a log (the journal), then applies it. After a crash it replays or discards incomplete journal entries, so recovery takes seconds. ext4's default mode journals metadata only and orders data writes before the metadata commits; full data journaling is safer and slower. Copy-on-write file systems (ZFS, Btrfs) get the same consistency by never overwriting live data in place.
45. What is the page cache, and what does fsync guarantee?
The kernel keeps recently read and written file data in RAM, the page cache. A write() normally returns once the data is in the page cache, not on disk; the kernel flushes dirty pages later. That is fast, and it means a power loss can lose writes the application believed succeeded. fsync(fd) blocks until the file's data and metadata reach stable storage. Databases call it on commit; durable file replacement means write to a temp file, fsync it, rename over the original, then fsync the directory.
46. Blocking, non-blocking and asynchronous I/O: what are select, epoll and io_uring?
Blocking I/O puts the thread to sleep until the operation completes. Non-blocking I/O returns immediately with "would block," so one thread can juggle many file descriptors if it knows which are ready. Readiness APIs tell it: select and poll scan the whole list on every call (O(n)), while epoll registers descriptors once and returns only the ready ones, which is what lets one thread handle tens of thousands of connections (Node.js, nginx and Redis are built on it or its equivalents, kqueue on BSD and macOS). io_uring goes further: a pair of ring buffers shared with the kernel for submitting operations and collecting completions, with few or no syscalls per operation, and it works for regular files too.
47. How does the kernel schedule disk I/O?
The block layer queues requests and an I/O scheduler orders them. For spinning disks, ordering to reduce seeks mattered a lot (the elevator algorithms). For SSDs and NVMe, which have no seek cost and deep hardware queues, the common choice is none or mq-deadline; bfq favours fairness and interactivity on desktops and slower devices, and kyber targets latency. Check and change it in /sys/block/<dev>/queue/scheduler. The interview point: the right scheduler depends on the device, and for fast NVMe, doing less is often best.
Part 7: Virtualization and Containers (48-50)
48. Virtual machine vs container?
A virtual machine runs a complete guest OS, including its own kernel, on virtualised hardware provided by a hypervisor. A container is a group of ordinary processes on the host kernel, isolated with namespaces and limited with cgroups. Containers start in milliseconds and have little overhead; VMs give stronger isolation because a kernel bug in a container affects the host, while a guest kernel is separated by the hypervisor. That is why multi-tenant platforms often run containers inside lightweight VMs (Firecracker, gVisor-style sandboxes).
49. What are namespaces and cgroups?
Namespaces control what a process can see: its own PID tree (it can be PID 1), network stack, mount table, hostname (UTS), IPC objects, user IDs and cgroup view. Cgroups control what a process can use: CPU shares and quotas, memory limits, I/O bandwidth, PID counts. A container is essentially namespaces plus cgroups plus a root file system image. Memory limits explain the most common container mystery: a process killed with exit code 137 while the host still has free memory.
50. Type 1 vs type 2 hypervisor?
A type 1 (bare-metal) hypervisor runs directly on the hardware and hosts guest VMs: VMware ESXi, Xen, Hyper-V; KVM turns the Linux kernel itself into one. A type 2 (hosted) hypervisor runs as an application on a host OS: VirtualBox, VMware Workstation. Type 1 is what clouds use, with hardware virtualisation extensions (Intel VT-x, AMD-V) doing most of the heavy lifting.
Bonus Part 8: Production Scenarios (51-56)
These are the questions where operating systems knowledge stops being theory. They come up in SRE, platform and backend loops, often as "here is a graph, what is happening?"
51. Load average is 40 on an 8-core box, but CPU usage is low. What is going on?
On Linux, load average counts tasks that are runnable plus tasks in uninterruptible sleep (D state), usually waiting on disk or network file system I/O. High load with idle CPUs points to I/O. Check vmstat 1 (the b column and wa), iostat -x 1 for device utilisation and latency, and ps -eo state,pid,cmd | grep '^D' to see which processes are stuck. A hung NFS mount is a classic cause.
52. A container keeps restarting with exit code 137. Why?
137 is 128 + 9: the process was killed with SIGKILL. In a container that is almost always the OOM killer enforcing the cgroup memory limit (question 41). Confirm with kubectl describe pod (reason OOMKilled) or the kernel log. Then decide whether the limit is too low or the process leaks. Watch for runtimes that size their heap from host memory rather than the container limit; modern JVMs and Node.js read cgroup limits, older versions did not. If the kill comes after a SIGTERM and a grace period instead, the process is not shutting down in time.
53. A service fails with "Too many open files."
Every socket, file and pipe uses a file descriptor, and the process hit its limit (ulimit -n, often 1024 by default for interactive shells; services set their own, for example LimitNOFILE in systemd). Check current usage with ls /proc/<pid>/fd | wc -l or lsof -p <pid>. If the count only grows, it is a leak: connections or files opened and never closed. Raising the limit is right for a legitimately busy server, wrong as a fix for a leak.
54. A service hangs with CPU at zero. How do you find out where?
A hang with idle CPU means threads are blocked: on a lock, on I/O or on each other. Take thread dumps (jstack for the JVM, py-spy dump for Python, gdb -p <pid> then thread apply all bt for native code, /proc/<pid>/task/*/stack for kernel-side waits) and look for threads waiting on locks held by other waiting threads: a cycle is a deadlock (question 27). The fix is a consistent lock order or a smaller critical section; the safety net is lock timeouts and an alert on stuck requests.
55. Memory usage looks huge in top. Is it a leak?
Look at the right column. VIRT/VSZ is mapped virtual address space, including reserved but untouched memory, shared libraries and memory-mapped files; it is often enormous and harmless. RES/RSS is what is actually resident in RAM, and it counts shared pages in every process that maps them. For a leak, watch RSS (or better, the process's anonymous memory, Pss or Private_Dirty in /proc/<pid>/smaps_rollup) grow steadily under constant load. Also remember that "free" memory being low on Linux is normal: the page cache uses spare RAM and gives it back on demand; look at "available."
56. Adding threads made a CPU-heavy job slower. Why?
More threads than cores means the extra threads only add context switches and cache thrashing (question 12). If they share a lock or write to the same cache line (false sharing), they serialise on it. For CPU-bound work, size the pool to the number of cores and partition the data so threads do not share mutable state. In languages with a global interpreter lock (CPython's default build), CPU-bound threads cannot run Python bytecode in parallel at all; use processes instead.
Quick-Fire: Operating System Interview Questions and Answers
- Kernel vs shell - the kernel manages hardware and resources; a shell is a user-space program that reads commands and asks the kernel to run them.
- What is a daemon? - a background process with no controlling terminal, usually started at boot (
sshd, cron).
- What does
nice do? - lowers (or, with privilege, raises) a process's scheduling priority; range -20 (highest) to 19 (lowest).
- Program vs process - a program is the file on disk; a process is a running instance of it, and one program can run as many processes.
- What is a file descriptor? - a small integer indexing the process's table of open files, sockets and pipes; 0, 1 and 2 are stdin, stdout and stderr.
- Copy-on-write - share pages read-only until someone writes, then copy only that page; makes
fork and snapshots cheap.
- Swap - disk space used to hold pages evicted from RAM; a little helps, heavy use means thrashing.
- Reentrant vs thread-safe - reentrant code can be interrupted and called again before the first call finishes (no shared state); thread-safe code works correctly when called from multiple threads (possibly using locks).
- Reader-writer lock - many concurrent readers or one writer; good for read-heavy data, can starve writers if not designed fairly.
- Memory barrier - an instruction that stops the CPU and compiler from reordering memory operations across it; what makes lock-free code correct on weakly ordered CPUs.
- Kernel panic - an unrecoverable kernel error; the system halts or reboots.
- What is
/proc? - a virtual file system exposing kernel and process information as files (/proc/<pid>/status, /proc/meminfo).
How to Practice for an Operating Systems Interview
- Look at real processes. Read
/proc/<pid>/status, run strace on a simple command, watch vmstat 1 while you compile something. Concepts stick when you have seen them in a terminal.
- Write the bugs on purpose. A two-thread program that races on a counter, one that deadlocks on two locks, one that leaks file descriptors. Then fix each one. This is the fastest way to answer Part 4 with confidence.
- Explain one mechanism a day out loud: a page fault, a context switch,
fork with copy-on-write. If you cannot explain it in two minutes without notes, it is not ready.
- Connect every answer to a production symptom. "Load average counts D-state tasks, so high load with idle CPUs means I/O" is the kind of sentence that separates a strong answer from a textbook one.
- Drill definitions under time pressure so the recall questions take seconds and leave time for the scenarios.
Keep going
- Drill it under pressure: the operating systems question bank covers processes, scheduling, deadlock, virtual memory and file systems as timed multiple-choice, the Bash & Linux bank covers the command line, and the free daily challenge gives you one a day with no account.
- Keep the references open: the concurrency essentials cheat sheet, the Linux performance essentials cheat sheet and the Unix essentials cheat sheet.
- Write code, not just answers: our coding challenges run your solution against real test cases in the browser.
- Round out the loop: Top 50 Linux, Bash, computer networking, Docker and C++ interview questions.
- Practise the follow-ups: the chat-based AI mock interview asks the "and what if the lock holder gets preempted?" questions a real round runs on.
#operatingsystems #os #concurrency #linux #interviews #backend #career