Tag: page fault

  • When Does Thrashing Occur? [Top 5 Powerful Causes & Smart Fixes Explained]

    When Does Thrashing Occur in operating systems, what causes it, how it affects performance, and the best techniques to prevent it.

    It was a late evening, and I was working on my laptop with multiple browser tabs, a code editor, and a few background applications running. Suddenly, everything began to lag — the cursor froze, apps stopped responding, and the hard drive light kept blinking continuously. That’s when I realized I was witnessing what operating system experts call thrashing.

    So, when does thrashing occur exactly?
    Thrashing occurs when an operating system spends more time swapping data between the main memory (RAM) and the disk than executing actual processes. This happens because the system runs too many programs simultaneously, exceeding the available memory, which causes constant page replacements and slows down performance dramatically.

    In this guide, we’ll break down why thrashing happens, how it affects performance, and what can be done to prevent it, explained in simple, easy-to-understand language.

    Introduction of When Does Thrashing Occur

    If you’ve ever noticed your computer suddenly slowing down, even though your processor isn’t fully used, chances are thrashing might be the reason.

    In operating systems, thrashing occurs when your system spends more time swapping pages between main memory and disk than executing actual processes. It’s one of the most serious performance issues in virtual memory management.

    Let’s dive deeper to understand when and why thrashing occurs, what it does to your system, and how to avoid it effectively.

    What Is Thrashing in Operating Systems?

    In simple terms, thrashing happens when the CPU is busy handling page faults instead of executing processes.

    This means the system is continuously swapping pages in and out of main memory (RAM) because there isn’t enough physical memory to handle the workload.

    When this happens, the CPU utilization drops dramatically, and the system appears to “freeze” or “hang.”

    When Does Thrashing Occur?

    Thrashing typically occurs when the system’s degree of multiprogramming is too high — in other words, when too many processes are running simultaneously and there’s not enough memory to support all their pages.

    Here’s the step-by-step sequence of events that lead to thrashing:

    1. High Degree of Multiprogramming:
      The operating system allows too many processes to run at once to maximize CPU utilization.
    2. Insufficient Physical Memory:
      Each process requires a certain number of pages to execute efficiently. If the total demand for memory exceeds available RAM, pages must be swapped out frequently.
    3. Frequent Page Faults:
      As processes execute, they continuously reference pages not currently in memory, causing repeated page faults.
    4. Increased Page Swapping:
      The OS continuously swaps pages between main memory and disk to satisfy these page faults.
    5. System Overhead:
      The CPU spends most of its time performing paging operations instead of useful computation.
    6. Performance Collapse:
      CPU utilization falls drastically, and overall system performance declines — this state is known as thrashing.

    Example of Thrashing

    Imagine a system with only 2 GB of RAM and 5 active processes, each needing 1 GB of memory.

    • Initially, all processes load some of their pages into memory.
    • As they execute, each process needs more pages, causing frequent page faults.
    • The OS keeps swapping pages in and out to accommodate them.

    The system eventually spends more time paging than processing, leading to thrashing.

    Effects of Thrashing

    Thrashing can severely impact system performance. Here’s what happens:

    • CPU Utilization Drops: Because the processor is mostly waiting for paging operations to complete.
    • System Becomes Unresponsive: Programs take too long to respond.
    • Disk I/O Increases: Excessive page swapping puts heavy load on disk drives.
    • Power Consumption Rises: Due to unnecessary read/write cycles.
    • Overall Throughput Decreases: The number of processes completed per unit time falls drastically.

    How to Detect Thrashing

    Operating systems use monitoring tools to detect thrashing based on the following signs:

    • High page fault rate
    • Low CPU utilization despite high multiprogramming
    • Increased I/O activity (especially disk operations)
    • Sluggish system response

    Tools like Task Manager (Windows) or top/vmstat (Linux) can help observe these symptoms.

    How to Prevent or Control Thrashing

    Here are the most effective ways to prevent or control thrashing in an operating system:

    1. Reduce Degree of Multiprogramming

    Decrease the number of active processes so that each has enough memory to execute efficiently.

    2. Use Local Replacement Algorithms

    Local page replacement ensures that a process only replaces its own pages, preventing interference from others.

    3. Increase Physical Memory (RAM)

    Adding more RAM can significantly reduce the chances of thrashing.

    4. Implement Working Set Model

    The OS tracks the working set (the set of pages a process is actively using). Ensuring all working sets fit in memory minimizes page faults.

    5. Use Page Fault Frequency (PFF) Control

    The OS monitors the page fault rate and dynamically adjusts the degree of multiprogramming.

    Thrashing vs. High Paging

    ParameterHigh PagingThrashing
    DefinitionOccasional page faults occurContinuous excessive paging
    CPU UtilizationSlightly affectedDrastically reduced
    CauseModerate memory shortageSevere memory shortage
    SolutionOptimize memory allocationReduce multiprogramming, add RAM

    Real-World Example

    When you open too many browser tabs, run multiple heavy apps, or play games alongside background downloads, your system might run out of RAM.

    Your OS then starts using the swap file (virtual memory on disk) to compensate. When this swap activity becomes excessive — your laptop starts lagging — that’s thrashing in action.

    Key Takeaways

    Thrashing occurs when the system spends more time swapping pages than executing processes.
    It happens mainly due to high multiprogramming and insufficient memory.
    Prevention techniques: Reduce process load, use the working set model, increase RAM, and monitor page fault rates.

    C code for Thrashing

    /**
     * thrash_demo.c
     *
     * Demonstrates memory pressure / heavy paging behavior.
     * Usage: ./thrash_demo <size_in_MB> <access_iterations> <access_pattern>
     *  - size_in_MB: amount of memory to allocate (in MB)
     *  - access_iterations: number of page accesses to perform
     *  - access_pattern: 0 = sequential, 1 = random
     *
     * Notes:
     *  - Compile with: gcc -O0 -std=c11 -Wall thrash_demo.c -o thrash_demo
     *  - Run with caution (may trigger swapping).
     */
    
    #define _POSIX_C_SOURCE 200809L
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include <string.h>
    #include <sys/resource.h>
    #include <time.h>
    #include <unistd.h>
    #include <errno.h>
    
    static long get_page_size(void) {
        long ps = sysconf(_SC_PAGESIZE);
        if (ps <= 0) ps = 4096;
        return ps;
    }
    
    static void print_rusage_delta(struct rusage *before, struct rusage *after) {
        long minflt = after->ru_minflt - before->ru_minflt;
        long majflt = after->ru_majflt - before->ru_majflt;
        printf("Page faults during run: minor = %ld, major = %ld\n", minflt, majflt);
    }
    
    static double timespec_diff_sec(const struct timespec *a, const struct timespec *b) {
        return (b->tv_sec - a->tv_sec) + (b->tv_nsec - a->tv_nsec) / 1e9;
    }
    
    int main(int argc, char **argv) {
        if (argc < 4) {
            fprintf(stderr, "Usage: %s <size_in_MB> <access_iterations> <access_pattern>\n", argv[0]);
            fprintf(stderr, "  access_pattern: 0 = sequential, 1 = random\n");
            return 1;
        }
    
        size_t size_mb = strtoull(argv[1], NULL, 10);
        unsigned long iterations = strtoul(argv[2], NULL, 10);
        int pattern = atoi(argv[3]);
    
        long page_size = get_page_size();
        size_t buf_bytes = size_mb * 1024ULL * 1024ULL;
        size_t pages = (buf_bytes + (page_size - 1)) / page_size;
    
        printf("Allocating %zu MB (%zu bytes), page size = %ld, pages = %zu\n",
               size_mb, buf_bytes, page_size, pages);
    
        // Try to allocate
        uint8_t *buf = malloc(buf_bytes);
        if (!buf) {
            perror("malloc");
            fprintf(stderr, "Allocation failed. Try smaller size.\n");
            return 1;
        }
    
        // Touch each page once (warm up) to map into page table (this will still allow swapping later)
        printf("Warming up: touching each page once to create mappings...\n");
        for (size_t i = 0; i < buf_bytes; i += page_size) {
            buf[i] = (uint8_t)(i & 0xFF);
        }
    
        // Get initial resource usage
        struct rusage ru_before, ru_after;
        if (getrusage(RUSAGE_SELF, &ru_before) != 0) {
            perror("getrusage");
        }
    
        // Prepare random index generator if needed
        srand((unsigned int)time(NULL) ^ (unsigned int)getpid());
    
        // Start timer
        struct timespec t_start, t_end;
        clock_gettime(CLOCK_MONOTONIC, &t_start);
    
        // Access pattern: either sequential over pages or random page accesses
        for (unsigned long it = 0; it < iterations; ++it) {
            size_t page_index;
            if (pattern == 0) {
                // sequential: cycle over pages
                page_index = it % pages;
            } else {
                // random: pick a page at random
                page_index = (size_t) ( ((uint64_t)rand() << 31 | rand()) % pages );
            }
            size_t offset = page_index * (size_t)page_size;
            // perform read+write to ensure write-back behavior
            uint8_t val = buf[offset];
            buf[offset] = val + 1;
        }
    
        clock_gettime(CLOCK_MONOTONIC, &t_end);
    
        // Collect resource usage after run
        if (getrusage(RUSAGE_SELF, &ru_after) != 0) {
            perror("getrusage");
        }
    
        double elapsed = timespec_diff_sec(&t_start, &t_end);
        printf("Accesses performed: %lu\n", iterations);
        printf("Elapsed time: %.3f seconds\n", elapsed);
        double accesses_per_sec = iterations / (elapsed > 0.0 ? elapsed : 1.0);
        printf("Accesses/sec: %.0f\n", accesses_per_sec);
    
        print_rusage_delta(&ru_before, &ru_after);
    
        // Print simple heuristic: if many major faults occurred, likely swap I/O happened
        long majfaults = ru_after.ru_majflt - ru_before.ru_majflt;
        if (majfaults > 0) {
            printf("Major page faults occurred (%ld) — data was loaded from disk (swap) during run.\n", majfaults);
            printf("This indicates heavy paging and could be a sign of thrashing if sustained with high CPU waits.\n");
        } else {
            printf("No major page faults observed during run. (Minor faults may still indicate page-table activity.)\n");
        }
    
        free(buf);
        return 0;
    }

    What the output means

    • Page faults during run: minor = X, major = Y
      • Minor faults: page mapped but not in RAM (lightweight) or copy-on-write type — not from disk.
      • Major faults: OS had to read page from disk (swap) — expensive and slows execution.
    • If you see many major faults and elapsed time is high, your test caused disk I/O for memory pages — this is the behavior that in extreme, sustained cases leads to thrashing.
    • If CPU utilization falls while major faults + I/O is very high on the system, that’s consistent with thrashing: the OS spends more time moving pages than running processes.

    How this ties to “When does thrashing occur”

    • Use this program to create memory pressure. When the sum of working sets of running processes exceeds available RAM, you’ll observe many major page faults as the OS swaps — that’s when thrashing can occur.
    • Real thrashing typically requires multiple processes competing for memory (not just a single test program). You can run multiple instances of this program or other memory-hungry apps simultaneously to reproduce a thrashing-like scenario

    FAQ: When Does Thrashing Occur?

    Q1. What exactly causes thrashing in an operating system?
    Thrashing occurs when the total demand for memory by all active processes exceeds the available physical memory, leading to excessive paging.

    Q2. How can you tell if your system is thrashing?
    If CPU usage drops while disk usage spikes and applications freeze or respond slowly, your system is likely thrashing.

    Q3. What is the main solution to prevent thrashing?
    Reduce the degree of multiprogramming or increase the amount of physical memory (RAM).

    Q4. Is thrashing common in modern systems?
    Modern OSs use smart memory management algorithms to minimize thrashing, but it can still occur during heavy multitasking or with limited RAM.

    Q5. What happens to CPU utilization during thrashing?
    It decreases sharply because most CPU cycles are wasted handling page faults rather than executing processes.

    Common Follow-up Question:

    Memory Protection Unit (MPU)

    Conclusion

    Thrashing is one of the most critical performance problems in operating systems. It happens when the system is overloaded with too many active processes, leading to constant page swapping between RAM and disk.

    By understanding when thrashing occurs, you can optimize memory usage, manage processes efficiently, and keep your system running smoothly.

  • What is Demand Paging: 7 Facts That Will Make You Understand It Better

    When you start learning about memory management in operating systems, one of the first concepts that can sound tricky yet fascinating is demand paging.
    So, what is demand paging, and why does it matter in modern computing?

    What is Demand Paging?

    Demand paging is a memory management technique used by operating systems to load pages into physical memory only when they are needed during program execution.

    In simpler terms, instead of loading the entire program into RAM at once, the operating system loads only the required parts (pages) on demand.
    This approach helps in saving memory, reducing load time, and allowing multiple programs to run efficiently at the same time.

    Think of it like this:
    When you open a large book, you don’t read every page right away — you open one page at a time as you go.
    That’s exactly how demand paging works with program pages.

    How Demand Paging Works

    Here’s the step-by-step process of how demand paging functions inside the system:

    1. Program Execution Begins:
      When a process starts, only a small part of it (like the first few pages) is loaded into memory.
    2. Page Fault Occurs:
      If the CPU tries to access a page that isn’t in physical memory, the operating system detects a page fault.
    3. Page Brought from Secondary Storage:
      The required page is then fetched from secondary storage (usually the hard disk) into RAM.
    4. Page Table Update:
      The OS updates the page table to mark that the page is now available in memory.
    5. Execution Resumes:
      The CPU resumes the process as if the page had been there all along.

    This entire process happens so fast that the user usually doesn’t notice it.

    Components Involved in Demand Paging

    To understand what is demand paging completely, you should know about its core components:

    • Page Table: Keeps track of whether a page is in memory or on disk.
    • Valid/Invalid Bit: Each page table entry contains a bit indicating if the page is valid (in memory) or invalid (on disk).
    • Secondary Storage: Stores the pages that are not currently in RAM.
    • Page Fault Handler: Handles the process of fetching the missing page when a page fault occurs.

    Advantages of Demand Paging

    Let’s look at the benefits that make demand paging a popular approach in operating systems:

    Efficient Memory Usage:
    Only necessary pages are loaded, which saves RAM space.

    Faster Startup Time:
    Programs can start running immediately without loading the entire code into memory.

    Better Multiprogramming:
    Since memory is used efficiently, more processes can run simultaneously.

    Reduced I/O Overhead:
    Only needed pages are transferred between disk and memory.

    Disadvantages of Demand Paging

    While demand paging is powerful, it’s not perfect. Here are some of its downsides:

    Page Fault Overhead:
    Each page fault causes a delay because the OS needs to fetch the missing page from disk.

    Thrashing:
    If too many page faults occur, the system may spend most of its time swapping pages instead of executing programs.

    Complex Implementation:
    Maintaining page tables and handling faults increases the complexity of the OS.

    Real-Life Example of Demand Paging

    Imagine you’re using a video editing app.
    When you open it, the operating system doesn’t load all the tools, filters, and resources into memory at once.
    Instead, it loads them on demand — when you click on a specific feature.
    This helps your system stay fast and responsive, even for heavy applications.

    That’s demand paging in action — efficient, smart, and user-friendly.

    C Program: Demand Paging Simulation

    #include <stdio.h>
    #include <stdlib.h>
    #include <stdbool.h>
    
    #define TOTAL_PAGES 10      // Total pages in program
    #define FRAME_SIZE 4        // Number of pages that can be in memory at once
    
    // Function to simulate loading a page into memory
    void loadPage(int pageNumber, int memory[], bool inMemory[]) {
        printf("Page fault: Loading page %d into memory.\n", pageNumber);
    
        // Find an empty frame or replace first page (FIFO replacement)
        bool loaded = false;
        for (int i = 0; i < FRAME_SIZE; i++) {
            if (memory[i] == -1) {
                memory[i] = pageNumber;
                inMemory[pageNumber] = true;
                loaded = true;
                break;
            }
        }
    
        if (!loaded) {
            printf("Memory full! Replacing page %d with page %d.\n", memory[0], pageNumber);
            inMemory[memory[0]] = false;
            memory[0] = pageNumber;
            inMemory[pageNumber] = true;
        }
    }
    
    // Function to simulate accessing a page
    void accessPage(int pageNumber, int memory[], bool inMemory[]) {
        printf("\nAccessing page %d...\n", pageNumber);
        if (inMemory[pageNumber]) {
            printf("Page %d is already in memory. No page fault.\n", pageNumber);
        } else {
            loadPage(pageNumber, memory, inMemory);
        }
    }
    
    int main() {
        int memory[FRAME_SIZE];
        bool inMemory[TOTAL_PAGES];
    
        // Initialize memory and inMemory flags
        for (int i = 0; i < FRAME_SIZE; i++) memory[i] = -1;
        for (int i = 0; i < TOTAL_PAGES; i++) inMemory[i] = false;
    
        // Simulated sequence of page accesses
        int pageRequests[] = {0, 2, 1, 3, 0, 4, 2, 5, 1, 0};
        int numRequests = sizeof(pageRequests) / sizeof(pageRequests[0]);
    
        for (int i = 0; i < numRequests; i++) {
            accessPage(pageRequests[i], memory, inMemory);
            printf("Current Memory: ");
            for (int j = 0; j < FRAME_SIZE; j++) {
                if (memory[j] != -1) printf("%d ", memory[j]);
                else printf("_ ");
            }
            printf("\n");
        }
    
        return 0;
    }
    

    Explanation of This Code

    • This simulates demand paging using page requests.
    • memory[] array represents the physical memory frames.
    • inMemory[] keeps track of which pages are currently in memory.
    • Whenever a page is accessed:
      • If it’s already in memory → no page fault.
      • If it’s not in memory → page fault occurs, and it is loaded into memory.
    • Uses FIFO (First-In-First-Out) page replacement for simplicity.

    Example Output of Demand Paging

    Accessing page 0...
    Page fault: Loading page 0 into memory.
    Current Memory: 0 _ _ _
    
    Accessing page 2...
    Page fault: Loading page 2 into memory.
    Current Memory: 0 2 _ _
    
    Accessing page 1...
    Page fault: Loading page 1 into memory.
    Current Memory: 0 2 1 _
    
    Accessing page 3...
    Page fault: Loading page 3 into memory.
    Current Memory: 0 2 1 3
    
    Accessing page 0...
    Page 0 is already in memory. No page fault.
    Current Memory: 0 2 1 3
    ...
    

    Difference Between Demand Paging and Pre-Paging

    FeatureDemand PagingPre-Paging
    Loading StrategyLoads pages only when neededLoads pages in advance
    Memory UsageMore efficientMight load unnecessary pages
    PerformanceCan cause delays due to page faultsReduces page faults but may waste memory
    Best Use CaseWhen working sets are smallWhen page access patterns are predictable

    Why Demand Paging Matters

    In modern systems like Windows, Linux, and QNX, demand paging ensures that applications run efficiently without exhausting system memory.
    It also plays a crucial role in virtual memory management, allowing systems to run large applications even with limited physical RAM.

    If you want to dive deeper into how operating systems handle process memory efficiently, you can explore this guide on differences between process and thread — it helps you understand how processes and threads share memory space.

    Summary of Demand Paging

    • Demand paging is a memory management technique where pages are loaded only when needed.
    • It helps optimize RAM usage and improve multitasking performance.
    • However, too many page faults can slow down the system (thrashing).
    • It’s widely used in modern operating systems to balance performance and efficiency.

    Demand Paging Key Takeaway

    The next time someone asks you, “What is demand paging?”, you can confidently say —
    “It’s a technique where the operating system loads program pages into memory only when they’re required, improving efficiency and enabling smooth multitasking.”

    Frequently Asked Questions (FAQ) on What is Demand Paging

    Q1. What is Demand Paging in an Operating System?

    Answer:
    Demand paging is a memory management technique where the operating system loads program pages into physical memory only when they are needed. It helps reduce memory usage and improves system performance by avoiding loading the entire program at once.

    Q2. What is the main purpose of Demand Paging?

    Answer:
    The main purpose of demand paging is to optimize memory usage and reduce program startup time. It allows the operating system to execute large programs efficiently even with limited RAM.

    Q3. What causes a Page Fault in Demand Paging?

    Answer:
    A page fault occurs when the CPU tries to access a page that is not currently in main memory. The operating system then retrieves that page from secondary storage and loads it into RAM.

    Q4. What are the advantages of Demand Paging?

    Answer:
    Some key advantages include:

    • Efficient use of memory
    • Faster program start-up
    • Better multiprogramming support
    • Reduced I/O operations

    Q5. What are the disadvantages of Demand Paging?

    Answer:
    The disadvantages are:

    • Increased page fault overhead
    • Risk of system thrashing if too many page faults occur
    • More complex memory management logic

    Q6. What is the difference between Demand Paging and Pre-Paging?

    Answer:
    In demand paging, pages are loaded only when required, whereas in pre-paging, the OS predicts and loads multiple pages in advance. Demand paging saves memory, while pre-paging aims to reduce future page faults.

    Q7. Where is Demand Paging used in real life?

    Answer:
    Demand paging is widely used in modern operating systems like Windows, Linux, macOS, and QNX, allowing them to handle large applications smoothly without consuming excessive physical memory.

    Q8. How does Demand Paging improve system performance?

    Answer:
    By loading only the necessary pages, demand paging reduces memory pressure and improves CPU utilization, enabling multiple applications to run efficiently at the same time.

    Q9. What is a Valid/Invalid bit in Demand Paging?

    Answer:
    Each entry in a page table has a valid/invalid bit that tells whether a page is currently in memory (valid) or stored on disk (invalid). This helps the OS detect when a page fault occurs.

    Q10. Can Demand Paging cause Thrashing

    Answer:
    Yes. If too many page faults happen in a short time, the system may enter a state called thrashing, where it spends most of its time swapping pages instead of executing processes.