windows3-2 Exercise 3: The Allocation Experiment With 1 GB ================================================================= Verification: Level 1 (read-only or short-lived allocation; run on the author's machine, no administrator rights). Prediction (work this out before running the script): Allocate 1 GB: this process's commit rises by about 1 GB and system Committed by about 1 GB; the working set and Available barely change. Touch half: working set up by about 0.5 GB and Available down by about 0.5 GB; Committed unchanged. Touch all: working set up by about 1 GB in total, Available down by about 1 GB. Free: everything returns to the starting values. ex3.ps1 (run it with: powershell -ExecutionPolicy Bypass -File ex3.ps1): # alloc.ps1: commit memory, then touch it, and watch which counters move. Frees everything on exit. param([int]$GB = 3) Add-Type -TypeDefinition @" using System; using System.Runtime.InteropServices; public static class Hog { public static IntPtr Alloc(long bytes) { return Marshal.AllocHGlobal(new IntPtr(bytes)); } public static void Touch(IntPtr p, long bytes) { for (long i = 0; i < bytes; i += 4096) Marshal.WriteByte(new IntPtr(p.ToInt64() + i), 1); } public static void Free(IntPtr p) { Marshal.FreeHGlobal(p); } } "@ function Show($label) { $me = Get-Process -Id $PID $m = @{} foreach ($s in (Get-Counter '\Memory\Available Bytes', '\Memory\Committed Bytes').CounterSamples) { $m[($s.Path -split '\\')[-1]] = $s.CookedValue } '{0,-22} this process: commit {1,6:N0} MB, working set {2,6:N0} MB | system: committed {3,6:N2} GB, available {4,6:N2} GB' -f $label, ($me.PrivateMemorySize64 / 1MB), ($me.WorkingSet64 / 1MB), ($m['committed bytes'] / 1GB), ($m['available bytes'] / 1GB) } $bytes = [long]$GB * 1GB Show 'start' $p = [Hog]::Alloc($bytes) Show "allocated $GB GB" [Hog]::Touch($p, $bytes / 2) Show 'touched half' [Hog]::Touch($p, $bytes) Show 'touched all' [Hog]::Free($p) Show 'freed' Output (real, from the author's machine on 2026-10-24; your numbers will differ): start this process: commit 53 MB, working set 76 MB | system: committed 23.73 GB, available 15.26 GB allocated 1 GB this process: commit 1,090 MB, working set 88 MB | system: committed 24.70 GB, available 15.29 GB touched half this process: commit 1,090 MB, working set 600 MB | system: committed 24.71 GB, available 14.76 GB touched all this process: commit 1,091 MB, working set 1,113 MB | system: committed 24.71 GB, available 14.26 GB freed this process: commit 65 MB, working set 89 MB | system: committed 23.72 GB, available 15.26 GB WHY THIS WORKS AS AN ANSWER --------------------------- Allocated 1 GB: commit 53 -> 1,090 MB (about +1 GB), working set 76 -> 88 MB, system Committed 23.73 -> 24.70 GB, Available unchanged (15.26 -> 15.29). Touched half: working set 600 MB, Available 14.76 GB (about 0.5 GB lower). Touched all: working set 1,113 MB, Available 14.26 GB (about 1 GB lower than the start). Freed: commit 65 MB, Available back to 15.26 GB. Each prediction held; the small differences from exact round numbers (88 MB rather than 76, for example) are the process's own bookkeeping and other programs moving a little while the script runs. The takeaway: commit is the promise (it moves at allocation), the working set and Available move only when the pages are touched. Common mistakes: expecting Available to fall at allocation time; expecting Committed to rise again when the memory is touched (it was committed already); and forgetting that the script runs in its own process, so the memory is released when it ends, even if the Free step were skipped.