Array (data structure) 2026-10-13
A data structure storing entries at numbered positions, usually starting at index zero. The fixed-capacity representation considered here puts equal-sized slots consecutively in computer memory. The number of occupied slots can be smaller than the capacity; unused slots provide room for later entries. An array of references stores consecutive references, while the objects they identify can be elsewhere. [ref]
Let the first slot have abstract address and each slot occupy address units. Then indexed access computes
For toy values , , the slots for start at ; index goes directly to through . These are illustrative slot addresses, not observed allocation addresses. Under the word-RAM (random-access machine) model for time complexity, word-sized arithmetic operations and any addressed computer memory access have constant cost, and the addresses and entries fit in words. Thus one array access takes time in Big O notation, independently of the index. This is the access assumption needed by binary search. [ref]
Inserting after in an array holding with one unused slot produces : first copy from slot to slot , then write into slot . Writing first would lose unless it had been saved separately. More generally, insert at index by copying occupied slots from right to left, then fill the gap; with spare capacity this moves entries and takes time in Big O notation, so insertion near the middle has time complexity. Removing an entry closes the gap by shifting later entries left. [ref]
A fixed-capacity array cannot accept another entry when full. A resizable representation can allocate a larger array and copy the entries. Doubling capacity when full gives append cost by amortized analysis over a sequence starting empty, but a single append that copies entries still has worst-case time complexity. The outline is a geometric series: copied capacities sum to , less than twice the number of appends that triggered the last copy. Middle insertion still pays for its shifts. [ref]
Byte 2026-10-13
A unit of information; throughout these examples, one byte contains eight bits and is the smallest independently addressed unit of computer memory.
Cache (computing) 2026-10-13
A store of selected information kept for faster reuse. A translation lookaside buffer is a memory cache of address translations; a buffer cache instead holds device-block contents.
For a data memory cache, the useful bargain is to keep a small selection of computer memory close to the CPU. A cache hit serves a read from that selection; a cache miss requires obtaining the contents elsewhere. Temporal locality helps a retained cache block serve repeated reads, and spatial locality helps one transferred cache line serve neighbouring bytes. Placement, capacity and LRU replacement determine whether that opportunity survives until the next read. [ref]
The worked memory access trace below uses twelve single-byte reads at these decimal physical addresses, in this fixed order:
Assume an initially empty fully associative cache, 16-byte aligned cache blocks, and capacity two cache slots: 32 bytes of cached data, excluding metadata. Use exact LRU replacement, refreshing recency on every read, including cache hits. Every cache miss fetches its requested cache line completely before the next read; only a full memory cache needs an eviction. There are no writes, fetching ahead of requests, external invalidations, or overlapping reads. All addresses denote ordinary cacheable computer memory, and address translation is outside this model. These are deliberately synthetic assumptions, not specifications of a particular CPU.
This makes the outcome reproducible from the memory access trace, rather than from an informal impression that data are “nearby” or “recent”. The cache line geometry below identifies the requested unit; fully associative cache enumerates the resulting states; average memory access time translates the counts into a simple timing calculation.
Cache line 2026-10-13
A fixed-sized, aligned block of consecutive bytes transferred and tracked as a unit by a data memory cache. Here cache line and cache block name that unit of data, including its identity in backing computer memory; a resident slot holds a copy. Reading one element can bring neighbouring elements into the same cache line, exploiting spatial locality.
For a nonnegative integer physical address and a cache line size bytes, Euclidean division gives the backing cache block number and offset :
Here the brackets denote the floor function and gives the remainder. Cache line contains bytes at physical addresses through . With , read address 52 selects cache block 3, spanning addresses 48–63, and offset 4. Addresses 48 and 52 therefore request the same cache line; addresses 15 and 16 request different cache lines despite being adjacent.
Figure 1.
Physical address 52 selects cache line 3 and offset 4; the resident copy occupies cache slot 0
. Details.
For a cache line size , the low bits give the offset. In a fully associative cache, all remaining bits identify the backing cache block as its cache tag; there are no address bits selecting a particular cache slot. An eight-bit illustration gives : four bits 0011 for cache block 3 and four bits 0100 for offset 4 in the binary numeral system. The eight-bit width is illustrative; the trace does not assume an actual eight-bit machine. [ref]
Distinguish this identity from a cache slot, which can hold different cache blocks over time. After read nine in the memory cache example, cache slot 0 contains cache line 3 and cache slot 1 contains cache line 0. Their cache tags identify 3 and 0; neither cache line number is its slot number. Some texts use “cache line” for the storage entry itself; this article reserves cache slot for that role.
Computer bus 2026-10-13
A computer bus connects components through agreed communication paths and transfer rules. On a shared computer bus, a CPU and a DMA engine can both want the same path to computer memory: attaching another initiator does not create another independent path. Bus arbitration chooses who may start; bus ownership states who may use each resource; bus throughput measures the useful data delivered. This makes sharing a performance question as well as a correctness question.
Figure 1.
Shared computer bus paths, bus arbitration, and address, data and control roles
. Details.
Computer memory 2026-10-13
Storage holding information used by a computer. Here, resident memory pages occupy main computer memory; a physical address identifies a location in the physical address system rather than an operating-system process's private numbering.
Context switch 2026-10-13
A context switch transfers CPU execution from one operating-system process or software thread to another while preserving enough execution context for the suspended task to resume. The operating-system kernel saves the outgoing task's processor registers, including its resume program counter and stack pointer, and restores the incoming task's saved state. Hardware entry and software switching divide this work differently across architectures; the diagram groups them into logical save and load steps. During the transition the same CPU executes the operating-system kernel's scheduler and switching code. [ref]
For a schematic switch from A to B, let A's resume program counter be , its stack pointer , and one illustrative data processor register contain 7. B's saved values are . Saving A retains in A's execution context; loading B establishes before B resumes. These are selected fields, not a complete architecture-specific execution context. Later restoring A recovers its 7 even though B has used the same physical processor register for 42.
Figure 1.
One CPU over time: save A's execution context, run the scheduler, and restore B's execution context
. Details.
The useful invariant is that each suspended task retains its own resume state, so another task's use of the processor registers does not erase it. This is what makes repeated turns under round-robin scheduling possible. Saving an execution context does not copy the entire address space. Switching between software threads of one operating-system process can retain the same address space; switching between operating-system processes with different address spaces may also require changing the memory management unit's translation context, such as the active page table and associated address space identifier, depending on the architecture. Their contents remain in computer memory. [ref]
Entering the operating-system kernel through an interrupt, synchronous processor exception or system call does not automatically imply a context switch to another task. The handler may return to the same task; process scheduling determines whether another runnable task should take over. A context switch consumes time, and a changed memory cache or translation lookaside buffer working environment can add subsequent costs. Those costs are excluded from the toy process scheduling timelines, which are calculations rather than operating system benchmarks. [ref][ref]
Conway Game of Life 2026-10-13
Conway's Game of Life is a cellular automaton in which a simple local rule produces patterns that remain still, pulse, or travel across a square grid. Choose the starting pattern; after that there are no player decisions. The Life blinker and Life glider below make the surprise concrete: the rule mentions only births and survival, yet repeated applications create a clock and a moving shape.
The standard board is infinite, with cells at ordered pairs of integers. At generation let be for a live cell and for a dead cell. Count all eight cells sharing an edge or a corner, excluding the center itself:
The local Boolean function defining the next generation is
This is the rule B3/S23: a dead cell is born with exactly three live neighbors; a live cell survives with exactly two or three. A live cell with zero or one, or with four through eight, dies. A dead cell with two stays dead. All counts and center states come from generation : this is a synchronous update, even if an algorithm computes its cells one at a time.[ref]
In particular, the two births in the Life blinker do not help any other cell survive until the following generation. Writing each answer over its old value and then reading that new value for another count changes the rule. The simplest correct algorithm reads one array and writes the next generation into a second array; swap their roles after the entire step. The one-row in-place Life update achieves the same rule with less auxiliary storage by preserving the old values that later counts still need.
A finite implementation must specify its boundary convention. Holding all cells outside the rectangle permanently dead can destroy a Life glider when it reaches the edge. Wrapping neighbor coordinates from one edge to the opposite edge allows interaction with patterns on the other side. Neither convention is the infinite board. The figures display finite windows into an infinite board initially dead everywhere except the stated live cells; the windows do not impose walls.
Conway's Game of Life illustrates emergence in a precise, modest sense: the Life glider's motion is a collective pattern derived from local birth and death, without a motion command. It has deterministic evolution; visually surprising behavior introduces no random choices. Nor do the words "alive" and "dead" make it an experimentally validated model of biology. The beauty is that the same rule yields a stable four-cell square, the Life blinker, and the Life glider: three qualitatively different behaviors from a handful of cells.
For the stable square, take the live set . Each live cell has three live neighbors, and every dead cell has at most two. The next generation is identical: this configuration is a fixed point of the global update function. In contrast, the Life blinker returns after two generations, and the Life glider returns only after allowing a translation.
The patterns are useful as small, exact checks of an algorithm: the square checks survival without births, the Life blinker checks births and deaths in one simultaneous step, and the Life glider checks several steps and diagonal neighbors. More elaborate constructions can encode data and assemble Boolean circuits; Johnston and Greene develop constructions that simulate arbitrary computation in their chapter 9. This is a statement about suitably designed patterns with enough space and time, not a claim that every starting pattern computes something useful or that a fixed finite board has unlimited computer memory.[ref]
Martin Gardner introduced Conway's Game of Life to his Scientific American readers in October 1970, reporting that Conway selected the rules after experimentation with patterns. The aim was sustained, varied behavior rather than immediate extinction or trivially demonstrable unlimited growth. These were mathematical explorations of chosen rules.[ref]
Gardner's hands-on procedure is still a useful experiment: place black counters for the current live cells; mark doomed counters by stacking another black counter; mark births with white counters; finish checking before removing the doomed stacks and turning white counters black. Count only the original black occupants. Repeat with three adjacent counters to obtain the Life blinker, then with the five coordinates of the Life glider. Recording each generation tests whether the procedure implements the rule; it does not measure a natural population.[ref]
Copy-on-write 2026-10-13
Copy-on-write defers copying until a modification needs private storage. With paging, separate address spaces can map their memory pages to the same page frames, using memory protection to prevent writes to the common contents. Reads need no copy. A permitted write to a shared page frame first separates the writer's storage, so the other operating-system process keeps the old contents. Sharing is safe because the common contents remain unchanged while shared; the logical private copies can still evolve independently.[ref]
Consider a fork-like model with parent A and child B. Each has a separate page table, with three inherited private, logically writable memory pages. Both initially map virtual page numbers 0x12, 0x13, 0x14 to page frames F0, F1, F2. The page table entries temporarily deny writes for copy-on-write; a read of x at offset 0x34 in virtual page 0x12 returns 7 in either address space. Separate page tables do not imply separate stored bytes.
Figure 1.
Before a write: two page tables map six memory pages to three shared page frames
. Details.
Now B writes x = 42. In this model, copy-on-write fault handling allocates F3, copies all of F0's contents into F3, redirects only B's page table entry, enables its write, and retries the store. A still reads 7 through F0; B reads 42 through F3 at the same virtual address. F1 and F2 remain shared. The reference counting labels count mappings in this example: F0 drops from two to one, while F3 starts at one. Updating one byte can therefore copy a whole memory page.
Figure 2.
After B writes: one new page frame, one whole-page copy, and independent contents at the same virtual address
. Details.
The attraction is avoiding work that may never be needed. If B only reads, this model makes no data copies; if B replaces its program and discards these mappings, copying them beforehand would have been wasted. Copy-on-write trades eager copying for protected sharing and later page faults. The page tables, reference counting, and operating-system process records still cost time and computer memory.[ref]
For a concrete operating system contract, the fork(2) manual for the Linux kernel documents copy-on-write, while its mmap(2) manual distinguishes MAP_PRIVATE from MAP_SHARED. Writes through MAP_PRIVATE are not propagated to other mappings or the underlying file; writes through MAP_SHARED are visible to other operating-system processes mapping that region. An inherited shared mapping therefore retains shared-write behavior. For a private memory-mapped file, visibility of later changes to the underlying file is unspecified: private writes alone do not guarantee a frozen snapshot of the file. [ref][ref]
Nor does fork make every resource independent. With the Linux kernel, inherited file descriptors refer to the same open file descriptions, including shared file positions. Special mapping policies can omit a region from inheritance or zero it in the child. Thus the diagrams describe ordinary inherited private memory pages, not every resource reachable by a parent. [ref]
Direct memory access 2026-10-13
Direct memory access transfers data between a device and computer memory without the CPU executing a copy instruction for each item. The CPU still sets up the operation and observes completion. DMA answers who moves the data; an interrupt answers how a need for attention is announced. A DMA transfer can therefore finish with interrupt-driven input-output or with polled input-output. [ref]
For a toy receive operation, the CPU arranges a four-byte DMA buffer and tells the device its DMA address, length and direction. The device writes the bytes A, B, C, D into that DMA buffer. After completion and any required DMA buffer synchronization, the CPU can read those four bytes. There are four payload bytes, but no four-item CPU copy loop on the device-to-computer memory path. This is a schematic example, not an instruction to operate real hardware.
Figure 1.
DMA separates the device-to-computer memory data path from CPU setup and completion control
. Details.
The useful separation is that the CPU can perform other work while a larger transfer proceeds. The reasoning is a division of responsibilities: setup specifies the destination and extent once; the transfer engine advances through the payload; completion reports the result. The data still crosses an interconnect such as a computer bus, which must share access among competing initiators. Setup, mapping, synchronization and completion cost work, so DMA does not promise a speedup for every transfer size. [ref]
Correctness also requires keeping the DMA buffer alive and coordinating its ownership until the device is finished. A DMA address need not equal a CPU virtual address or physical address. An IOMMU, when present and configured, translates device addresses and can restrict access to authorized computer memory; it is not the CPU's memory management unit. Operating-system process isolation through virtual memory alone does not establish those device-access restrictions. [ref][ref]
DMA buffer 2026-10-13
A region of computer memory prepared for DMA. In the four-byte receive example it is the payload destination, and must remain available until the transfer and required DMA buffer synchronization are complete.
Communication between operating-system processes, including controlled message delivery and deliberately shared computer memory. A microkernel supplies IPC across protection domains, allowing user-space services to cooperate without making all their private computer memory accessible to each other.
Linked list 2026-10-13
A data structure representing a sequence through linked list nodes and links between them. In the singly linked representation used here, each linked list node holds an item and a next reference to its successor. head identifies the first linked list node; the final next is null, meaning no successor. An empty linked list has head = null. Sedgewick and Wayne use this representation to implement both a stack and a FIFO queue. [ref]
For , place the linked list nodes at conceptual computer memory positions , respectively. These deliberately separated labels describe a toy layout, not actual pointer values. The sequence order comes from the links, not increasing positions. To read index , begin at head and follow two next references. For index , this takes link-following steps and time complexity, hence in the worst case for linked list nodes, under the constant-cost operations assumed for the array example. [ref]
Suppose a reference to the existing linked list node is already known. To insert a fresh linked list node after it, first set X.next = B.next, preserving the old successor , and then set B.next = X. The result is ; none of the old items moves. Reversing these assignments would read the newly changed B.next and set X.next = X, losing the route to from head. This is a two-update algorithm correctness argument, rather than a claim that finding the insertion location is free.
The two pointer updates take time in Big O notation. The complete insertion has time complexity if the predecessor is already known, allocating and initializing the fixed-size linked list node costs , and copying its item has constant cost. Finding from head can instead cost ; a position described only by an index does not confer the constant-cost advantage. This makes a linked list useful when an algorithm already holds the needed linked list node, or repeatedly works at the front as a stack does.
Deletion similarly needs the incoming link: to remove after known , set B.next = X.next. A reference to alone does not identify its predecessor in this singly linked representation. The head is a special case: after checking for a nonempty linked list, remove it with head = head.next. If a tail reference is also maintained, deleting the only linked list node must clear that reference too; a stored length must also be updated. Removing a linked list node from the sequence and reclaiming its storage are separate responsibilities. [ref]
There are practical costs beyond Big O notation. Each singly linked linked list node needs a successor reference in addition to its item; separate allocation may add further overhead, while an array can reserve unused capacity. Consecutive array slots can make a scan reuse nearby contents already brought into a memory cache; separated linked list nodes can make link following wait for successive computer memory fetches. These are layout-dependent effects, not a guarantee that every array operation beats every linked list operation on every machine. An array of references can still lead to scattered objects, and linked list nodes can be allocated close together. [ref]