Prepare for Operating System interview questions grouped by experience level.
Operating System Interview Question & Answers
0-2 Years
An operating system is genuinely the software layer sitting between a computer's hardware and the applications actually running on it, managing hardware resources, memory, CPU, storage, and providing a genuinely consistent interface applications can use without needing to directly control the actual hardware themselves.
Process management, actually running and scheduling multiple programs. Memory management, allocating and tracking memory usage. File system management, organizing data storage. Device management, coordinating input and output hardware. Together these let an application genuinely focus on its own logic rather than directly managing hardware.
A single-tasking OS can genuinely run only one program at a time. A multitasking OS can genuinely run several programs seemingly simultaneously, rapidly switching the CPU's attention between them so quickly that it genuinely appears, to a user, as though they're actually all running at the exact same time.
The kernel is the genuine core component of an operating system, managing the most fundamental interactions with hardware, memory, CPU scheduling, directly. Everything else in the OS, utilities, user interfaces, genuinely builds on top of the services the kernel actually provides.
A monolithic kernel genuinely runs most operating system services, device drivers, file systems, within one single, large kernel space. A microkernel keeps genuinely only the most essential functions in kernel space, running other services, like device drivers, as genuinely separate user-space processes instead.
User mode genuinely restricts a running program from directly accessing hardware or genuinely critical system resources. Kernel mode has genuinely full, unrestricted access to hardware and system resources. A regular application genuinely runs in user mode, and it requests a genuinely privileged operation through a system call, which temporarily switches execution into kernel mode.
A process is a genuinely running instance of a program, including its own actual memory space, its current execution state, and the resources it's genuinely currently using, distinct from the program itself, which is just genuinely static code sitting on disk until it's actually executed.
New (being created), Ready (waiting for the genuine CPU to actually become available), Running (currently executing on the CPU), Waiting (blocked, waiting for a genuine event like I/O to complete), and Terminated (finished execution).
A PCB is a genuine data structure the operating system maintains for every single process, storing its current state, its CPU register values, its memory allocation details, and other genuinely necessary bookkeeping information needed to actually manage and, if needed, later resume that specific process.
A program is genuinely static, a set of instructions stored on disk, doing nothing on its own until it's actually executed. A process is a genuinely running instance of that program, actively using CPU time and memory, with its own genuine current state that changes as it actually executes.
Context switching is the operating system genuinely saving one process's own current state and loading another's, so the CPU can actually switch which process it's genuinely executing. It has a real cost because saving and restoring that state, along with genuinely reloading CPU caches, takes actual, measurable time that isn't spent doing genuinely useful work.
A parent process genuinely creates a child process, typically through a system call like fork(). The child process starts as a genuine copy of the parent (in a Unix-like system) and can then actually run its own genuinely independent code, while the parent can optionally wait for that child to actually finish.
A thread is a genuinely lighter-weight unit of execution within a process, sharing that process's own memory space with any genuinely other threads in the same process. A process has its own genuinely completely separate, isolated memory space, while multiple threads within the exact same process genuinely share that one memory space together.
Threads genuinely share memory directly, avoiding the overhead of inter-process communication that separate processes would genuinely require to actually share data. Creating and switching between threads is also generally genuinely lighter weight, faster, than doing the exact same thing with full, separate processes.
Multithreading lets a genuinely single program run multiple threads concurrently, letting it actually perform several tasks simultaneously, or at least appear to, by rapidly switching the CPU's attention between the genuinely different threads.
A user-level thread is genuinely managed entirely by a library within the process itself, with the kernel completely unaware of it existing at all. A kernel-level thread is genuinely managed directly by the operating system kernel, which can actually schedule it independently across multiple genuine CPU cores.
A race condition can genuinely occur, where the actual outcome of the program depends unpredictably on the exact timing of how the genuinely different threads happen to interleave their access to that shared data, potentially producing an incorrect or genuinely inconsistent result.
The main thread is the genuine, original thread a program starts executing on. In certain environments, like a graphical user interface, only the main thread is genuinely allowed to actually update the UI directly, which is exactly why a long-running task is typically genuinely offloaded to a separate, background thread instead.
CPU registers are the genuinely fastest and smallest. Cache memory (L1, L2, L3) is next. Main memory (RAM) follows. Secondary storage, like an SSD or hard drive, is the genuinely slowest but largest. Each level genuinely trades capacity for speed, with faster storage generally being genuinely more expensive per unit of capacity.
Primary memory (RAM) is genuinely volatile, losing its content when power is lost, but is much faster to actually access. Secondary storage, like a hard drive or SSD, is genuinely non-volatile, retaining its content without power, but is meaningfully slower for the CPU to actually access directly.
Virtual memory lets an operating system genuinely give each process the illusion of having its own large, continuous, private memory space, even though the actual underlying physical RAM might be genuinely smaller or shared among multiple, genuinely different processes.
Paging divides genuinely both physical memory and a process's own virtual address space into fixed-size blocks called pages. It solves the genuine problem of memory fragmentation that would otherwise occur if memory had to be allocated in genuinely large, contiguous chunks, letting a process's memory be spread across genuinely non-contiguous physical locations instead.
A page fault occurs when a process genuinely tries to access a page that's not currently actually loaded into physical memory. The operating system genuinely pauses that process, loads the needed page from secondary storage into memory, and then genuinely resumes the process from exactly where it left off.
Internal fragmentation happens when an allocated block of memory is genuinely larger than what's actually needed, wasting the unused, leftover space within that specific block. External fragmentation happens when genuinely enough total free memory exists, but it's scattered in small, non-contiguous pieces, none large enough on its own to actually satisfy a specific request.
Since paging divides memory into fixed-size pages that don't need to sit contiguously in physical memory, a process's pages can be scattered anywhere free space exists, rather than requiring one single, large, contiguous block. This genuinely eliminates external fragmentation entirely, though it can still leave a small amount of internal fragmentation within the very last, partially-used page.
CPU scheduling decides which genuinely ready process actually gets to run on the CPU next, and for how long. It's genuinely needed because a system typically has genuinely far more processes wanting CPU time than it actually has CPU cores available to run them simultaneously.
FCFS genuinely runs processes in the exact order they actually arrived, with no consideration for how long each one actually takes. A genuine drawback is the convoy effect, where a genuinely long process running first can make every subsequent, potentially much shorter process wait an unfairly long time.
SJF genuinely selects the process with the actual shortest expected execution time to run next, which minimizes genuine average waiting time across all processes, though it genuinely requires knowing (or accurately estimating) each process's actual execution time in advance, which isn't always realistically possible.
A preemptive algorithm can genuinely interrupt a currently running process to actually switch to a different one, typically because a genuinely higher-priority process became ready, or a time slice expired. A non-preemptive algorithm genuinely lets a running process continue until it either finishes or voluntarily gives up the CPU itself.
A time quantum is the genuine fixed amount of CPU time each process is allowed to actually run before being preempted and moved to the back of the genuine ready queue, letting Round Robin fairly, cyclically give every process a genuinely equal, repeated turn.
Common genuine goals include minimizing average waiting time, minimizing turnaround time (the total time from a process's arrival to its completion), maximizing CPU utilization, and ensuring genuine fairness so no process is starved of CPU time indefinitely.
A file system organizes how data is genuinely stored and retrieved on a storage device, providing a genuine structure, files and directories, that lets a user or an application actually find and manage data without needing to know the actual, raw physical layout of the underlying storage hardware.
A file genuinely stores actual data, text, an image, executable code. A directory (or folder) genuinely organizes files (and other, genuinely nested directories) into a hierarchical structure, without itself storing genuine file content directly.
Creating, opening, reading, writing, and deleting a file, along with genuinely organizing files into directories, and managing file permissions controlling who's genuinely allowed to actually access or modify a specific file.
Metadata is genuine information about a file, distinct from the file's own actual content, typically including its size, its creation and last-modified timestamps, its owner, and its genuine permission settings, all managed by the file system itself.
An absolute path genuinely starts from the root directory and fully specifies a file's genuine, exact location regardless of the current working directory. A relative path is genuinely interpreted relative to the current directory, pointing to a genuinely different actual location depending on where you currently actually are.
3-6 Years
A race condition occurs when genuinely multiple processes or threads access shared data concurrently, and the actual final outcome depends unpredictably on the exact, precise timing of that access, potentially producing a genuinely incorrect or inconsistent result depending on which one happens to actually run first.
A critical section is a genuine segment of code that accesses shared resources, and it needs protection because if genuinely multiple processes or threads execute it concurrently without coordination, the shared resource can end up in a genuinely corrupted or inconsistent state.
Mutual exclusion ensures that only genuinely one process or thread can actually execute a critical section at any given time, solving the genuine problem of concurrent, uncoordinated access to shared data that would otherwise genuinely cause a race condition.
A mutex genuinely allows only one thread to actually hold it at a time, and typically only the thread that genuinely acquired it can release it, making it well suited for protecting a single critical section. A semaphore can genuinely allow a specified number of threads through simultaneously, and can genuinely be released by a different thread than the one that acquired it, giving it more general, flexible use cases.
A binary semaphore can genuinely only take a value of 0 or 1, functionally behaving similarly to a mutex, though the two genuinely differ in some subtle semantic details, like ownership rules, and are genuinely conceptually distinct constructs even when they behave similarly in the simplest, most basic case.
A deadlock happens when genuinely two or more processes are each waiting on a resource the other one currently holds, so neither process can ever actually proceed, leaving both genuinely stuck indefinitely waiting for each other.
Mutual exclusion (a resource can genuinely only be held by one process at a time), hold and wait (a process genuinely holds one resource while waiting for another), no preemption (a resource can't genuinely be forcibly taken away), and circular wait (a genuine cycle of processes each waiting on the next).
Deadlock prevention genuinely eliminates at least one of the four necessary conditions entirely, structurally making a deadlock impossible. Deadlock avoidance genuinely allows all four conditions to potentially exist but carefully makes resource allocation decisions at runtime specifically to avoid ever actually entering an unsafe state that could lead to one.
The Banker's Algorithm is a genuine deadlock avoidance algorithm that decides whether granting a genuine resource request would leave the system in a safe state, one where every process could still eventually complete, before actually granting that request.
Common approaches include genuinely terminating one or more of the deadlocked processes, forcibly freeing up the resources they held, or genuinely preempting a resource from one process and giving it to another, breaking the circular wait condition that's actually causing the deadlock to persist.
Priority scheduling genuinely runs the process with the highest assigned priority first. A genuine risk is starvation, where a genuinely low-priority process could theoretically wait indefinitely if genuinely higher-priority processes keep continuously arriving and taking precedence ahead of it.
Aging genuinely gradually increases a waiting process's own priority the longer it actually waits, eventually ensuring even a genuinely originally low-priority process will actually get its turn on the CPU, preventing it from being starved indefinitely by a continuous stream of higher-priority arrivals.
A multilevel queue genuinely divides the ready queue into several separate queues, often based on process type or priority, like a genuinely separate queue for interactive processes versus batch processes, with each queue potentially using its own genuinely different scheduling algorithm.
A multilevel queue genuinely assigns a process to a fixed queue permanently. A multilevel feedback queue lets a process genuinely move between different queues over time, based on its actual observed behavior, like being moved to a genuinely lower-priority queue if it consistently uses its full time quantum, suggesting it's a more CPU-intensive process.
Turnaround time is the genuine total time from a process's arrival to its actual completion. Waiting time is the genuine turnaround time minus the process's own actual burst (execution) time, representing the time it genuinely spent waiting in the ready queue rather than actually executing on the CPU.
Segmentation divides a process's memory into genuinely variable-sized, logically meaningful segments, like code, data, and stack, each representing a genuine logical unit. Paging instead divides memory into genuinely fixed-size pages with no inherent logical meaning attached to any specific page.
A page table genuinely maps a process's virtual pages to their actual physical frame locations in memory. A segment table genuinely maps a process's logical segments to their actual physical memory locations, along with each segment's own actual, genuinely variable length.
Demand paging genuinely loads a page into physical memory only when it's actually needed, rather than loading a process's entire memory footprint upfront. It's used because it genuinely lets more processes run concurrently than would actually physically fit in memory all at once, since not every page is genuinely needed at the exact same time.
FIFO replaces the genuinely oldest loaded page. LRU (Least Recently Used) replaces the page that hasn't genuinely been accessed for the longest time. Optimal replaces the page that genuinely won't be needed again for the longest time in the future, which is theoretically ideal but genuinely impossible to actually implement in practice, since it requires knowing the future.
A thread pool maintains a genuinely fixed set of reusable worker threads, letting you submit tasks without genuinely creating and destroying a brand new thread for every single individual piece of work. It solves the genuine problem of thread creation overhead becoming a real bottleneck when a large, genuinely rapid volume of small tasks needs to actually be processed.
The producer-consumer problem involves genuinely one or more producer threads adding items to a shared buffer, and genuinely one or more consumer threads removing them, requiring careful coordination so a producer doesn't genuinely overflow a full buffer and a consumer doesn't genuinely try to read from an empty one. Semaphores are commonly used to actually coordinate this.
A spinlock genuinely keeps a thread actively checking, in a tight loop, whether a lock has become available, consuming CPU time the entire wait. A blocking lock genuinely suspends the waiting thread entirely, letting the CPU actually do other work, and wakes it back up once the lock genuinely becomes available.
A barrier makes every thread in a group wait at that specific point until all of them have genuinely reached it, before any single one is allowed to actually proceed further. It's genuinely commonly used in a parallel computation where every thread needs to finish one phase of work before any thread can safely begin the next phase, which depends on the previous phase being genuinely fully complete.
If a lock is genuinely expected to be held for only a very short time, the overhead of genuinely suspending and later waking a thread through a blocking lock can actually exceed the cost of simply spinning briefly, making a spinlock genuinely faster overall for that specific, short-duration case.
6-8 Years
A monitor is a genuinely higher-level synchronization construct, combining mutual exclusion with the ability to actually wait for a specific condition, bundling both a lock and condition variables together into one cohesive construct, rather than requiring a programmer to manually coordinate a genuinely separate mutex and condition variable themselves.
The reader-writer problem involves genuinely multiple readers being allowed to access shared data simultaneously, since reading doesn't genuinely modify anything, but a writer needing genuinely exclusive access, since a write could otherwise conflict with a concurrent read or another concurrent write.
The dining philosophers problem models genuinely several processes each needing two shared resources (forks) to actually proceed, illustrating the genuine risk of deadlock when resources are acquired in an genuinely inconsistent order across different processes, a classic example used to reason about deadlock and genuine resource allocation strategy.
One genuine solution has philosophers pick up their two forks in a consistently defined global order, like always the lower-numbered fork first, which genuinely breaks the circular wait condition that would otherwise allow a deadlock to actually form.
A condition variable lets a thread genuinely wait, while releasing an associated mutex, until another thread genuinely signals that a specific condition has actually become true, then reacquires that mutex before continuing. A plain mutex alone genuinely provides no way for a thread to efficiently wait for a condition without repeatedly, wastefully checking it in a loop.
Priority inversion happens when a genuinely low-priority process holds a lock a genuinely higher-priority process actually needs, and a medium-priority process preempts the low-priority one, effectively letting the medium-priority process indirectly delay the genuinely higher-priority one. Priority inheritance genuinely temporarily raises the low-priority process's priority while it holds that contested lock, preventing it from actually being preempted in the meantime.
In a deadlock, processes are stuck waiting and make no progress at all. In a livelock, processes keep actively changing state in response to each other, trying to avoid a conflict, but never actually make real progress either, both busy and stuck at the same time. A classic example is two processes each politely trying to yield to the other repeatedly, in a loop that never resolves.
A TLB is a genuinely small, fast hardware cache storing recent virtual-to-physical address translations. It solves the genuine problem of a full page table lookup being relatively slow, letting a genuinely frequently accessed translation be retrieved almost instantly from the TLB instead of requiring a full, slower page table walk every single time.
Thrashing occurs when a system spends genuinely more time swapping pages in and out of memory than actually executing real, useful work, typically caused by genuinely too many processes competing for too little available physical memory, forcing constant, excessive page faulting.
The working set model tracks the genuine set of pages a process has actually accessed recently, and ensures enough physical memory is genuinely allocated to hold that process's own current working set. It helps address thrashing by genuinely preventing a process from being given too little memory to actually hold what it's genuinely, actively using.
Copy-on-write lets genuinely two processes initially share the exact same physical memory pages, only actually creating a genuinely separate copy of a specific page once one of the processes actually tries to modify it. It's genuinely commonly used when a process is forked, since the child initially shares its parent's memory rather than immediately, wastefully duplicating it all upfront.
Memory-mapped I/O maps a file's genuine contents directly into a process's own virtual address space, letting the process actually access file data through simple memory reads and writes rather than explicit read() and write() system calls, which can genuinely improve performance by letting the operating system's own existing paging mechanism handle the actual, underlying I/O.
8-10 Years
A distributed operating system manages resources across genuinely multiple, physically separate machines, presenting them to an application as though they were genuinely one single, unified system, unlike a traditional OS, which genuinely manages resources on just one physical machine alone.
Clock synchronization ensures genuinely separate machines in a distributed system agree closely enough on the actual current time, which matters because many distributed algorithms genuinely rely on timestamps to actually determine the correct order of events across machines that don't naturally share one single, unified clock.
A physical clock genuinely measures actual, real-world elapsed time, and different machines' physical clocks can genuinely drift apart from each other over time. A logical clock, like a Lamport timestamp, doesn't genuinely track real time at all, but instead captures the genuine causal ordering of events across a distributed system reliably.
The CAP theorem states a distributed system can genuinely guarantee at most two of three properties at once: Consistency (every node sees the same data at the same time), Availability (every request gets a response), and Partition tolerance (the system keeps working despite a network partition). Since a network partition is a genuinely real possibility, the practical design choice usually comes down to favoring consistency or availability when a partition genuinely occurs.
A distributed deadlock spans genuinely multiple machines, with no single machine having genuinely complete, immediate visibility into the entire resource allocation state across the whole system. Detecting it genuinely requires machines to actually communicate and share state information with each other, adding real complexity and latency that a genuinely single-machine deadlock detection algorithm doesn't have to deal with.
Two-phase commit coordinates a genuine transaction across multiple nodes through a genuine prepare phase, where every node confirms it's genuinely ready to commit, followed by a genuine commit phase, where every node actually applies the change together. It solves the genuine problem of ensuring every node either commits or aborts together, maintaining a genuinely consistent outcome across the whole distributed transaction.
Load balancing distributes genuine work evenly across multiple available machines or processing units, preventing any single one from becoming a genuinely overloaded bottleneck while others sit comparatively idle, which is exactly what actually lets a distributed system scale effectively as overall demand genuinely grows.
A system call requests a genuine service directly from the operating system's own kernel, like reading a file or allocating memory, whereas a regular function call genuinely executes entirely within the current process's own user-space code, with no genuine involvement from the kernel at all.
Virtualization lets genuinely multiple operating systems (or multiple instances of the same one) run on a single genuine physical machine simultaneously, each believing it has its own genuinely dedicated hardware. It solves the genuine problem of underutilized physical hardware, letting one genuine physical machine efficiently host several genuinely separate, isolated workloads.
A Type 1 hypervisor runs genuinely directly on the physical hardware, with no underlying host operating system at all, generally offering better performance. A Type 2 hypervisor runs genuinely as an application on top of an existing host operating system, generally simpler to actually set up but carrying slightly more genuine overhead.
A container shares the genuine host machine's own operating system kernel, only isolating the application and its dependencies. A virtual machine genuinely virtualizes an entire separate computer, including its own full operating system kernel, making containers meaningfully lighter and faster to actually start than a full virtual machine.
An RTOS guarantees that a genuinely specific task will actually complete within a strict, defined time constraint, prioritizing genuine predictability above all else. A general-purpose operating system, like a typical desktop OS, genuinely optimizes for overall throughput and responsiveness, without offering that same genuine, strict timing guarantee for any specific individual task.
A hard real-time system genuinely, absolutely must meet its timing deadline, and missing one is considered a genuine, complete system failure, like a car's own airbag deployment system. A soft real-time system genuinely prefers to meet its deadline, but an occasional missed deadline degrades quality rather than causing a genuinely catastrophic failure, like a video streaming application experiencing an occasional buffering delay.
10+ Years
I'd weigh the actual, concrete need for a genuinely strict, guaranteed timing deadline, is a missed deadline genuinely catastrophic or merely inconvenient, against the real, added complexity and cost an RTOS typically introduces compared to a genuinely more familiar, general-purpose operating system.
I'd use OS-level tools, like a system profiler showing CPU scheduling activity, context switch frequency, and page fault rate, to genuinely rule in or rule out the operating system layer as the actual cause, rather than assuming the application code itself is genuinely always the culprit by default.
I check whether shared data access is genuinely properly protected against a race condition, whether the design could genuinely lead to a deadlock given how locks are actually acquired, and whether the chosen synchronization primitive, a mutex versus a semaphore, genuinely fits the actual specific need.
I'd document the handful of concurrency patterns and pitfalls that actually matter most, with genuine, concrete examples of a real problem each one solves or avoids, rather than a purely abstract, theoretical treatment of operating system concepts nobody actually connects back to real, practical code.
I'd weigh container's genuine advantages, faster startup, less overhead, better resource density, against any genuinely specific isolation or compatibility requirement that might actually still favor a full virtual machine, like needing to genuinely run a completely different operating system kernel than the host provides.
I'd check system-level metrics, CPU run queue length, context switch rate, page fault rate, and swap usage, over the genuine time window the slowness actually occurred, since these often reveal whether the OS itself is genuinely struggling under load, distinct from the application's own code being the actual bottleneck.
Track CPU utilization, memory usage and available swap, disk I/O wait time, and open file descriptor count, alerting on meaningful deviation from an established, normal baseline. A gradually rising memory usage or file descriptor count trend is often a genuine early warning sign of a resource leak well before it actually causes a hard failure.
I'd weigh the genuine, actual workload's characteristics rather than assuming more threads always genuinely helps. Beyond a certain point, adding threads can actually hurt performance due to increased context-switching overhead and lock contention, so I'd benchmark with a genuinely realistic workload rather than assuming more concurrency is automatically always better.
I'd check actual memory usage trends leading up to each kill to genuinely determine if it's a slow, steady leak or a genuinely sudden spike, and consider a temporary mitigation, like increasing the memory limit or scheduling a genuinely proactive restart, while properly investigating the actual, real root cause.
I'd load test with a genuinely realistic workload, monitoring actual CPU, memory, and I/O utilization under that load, and identify which specific resource is genuinely likely to become the actual bottleneck first, rather than assuming every resource will genuinely scale proportionally together.
This is a judgment question interviewers use to see how you reason under genuine uncertainty, not to test a specific textbook fact. A strong answer names the actual constraint that forced the decision, the realistic options that were genuinely on the table, why you picked one knowing it wasn't guaranteed to be right, and what you'd do differently with what you know now.
I'd walk through an actual, real deadlock scenario together, tracing exactly how two genuinely differently-ordered lock acquisitions could actually cause a real deadlock, rather than explaining the risk purely in the abstract. Seeing a genuinely real deadlock reproduce firsthand tends to build that specific caution far more effectively than a general warning alone.
I'd point to a specific, real, already-experienced performance issue that was genuinely only actually diagnosable by looking at OS-level metrics, and show concretely how that deeper understanding would have genuinely sped up finding the real, actual root cause much sooner.
I'd bring the actual, concrete access pattern into the discussion, how many readers, how many writers, how contended the resource genuinely is expected to be, rather than a general, abstract preference for one synchronization primitive over another. Grounding the discussion in the specific, real workload resolves it faster than an abstract debate.
I'd translate the request into terms leadership already tracks: a quick fix that only masks a symptom often recurs, costing more total engineering time across several incidents than properly diagnosing and fixing the actual root cause once. Framed as total cost avoided rather than extra upfront investigation time, it competes far better for the time and patience needed to actually do it properly.




