Table of Contents

Class IosMemory

Namespace
VpnHood.Core.Client.Devices.Ios
Assembly
VpnHood.Core.Client.Devices.Ios.dll

iOS VhMemory implementation. It reads on demand (no background sampler, no cached global): each call issues fresh mach/Foundation queries and returns the live values. The process footprint comes from mach TASK_VM_INFO (phys_footprint — the number the ~52 MB Network Extension jetsam limit is enforced on); total system memory from NSProcessInfo.PhysicalMemory.

public sealed class IosMemory : VhMemory
Inheritance
IosMemory
Inherited Members

Remarks

A host installs it as Instance via Install() at init — in both processes: the app (IosDevice constructor) and the extension (IosVpnService.StartTunnel) — and each reports its OWN process's footprint, so it works wherever it's asked. Consumers (the iOS QUIC download brake in IosQuicStream and the TCP stack's +CONN/-CONN log annotation) then read live values without any dependency on this class. The gated ext-mem.log probe (IosMemoryMonitor, the extension's) also reads the fuller iOS-specific breakdown via TryRead(out FootprintInfo) on its own thread. System-wide "used" memory is left null here (it needs host_statistics, not worth the native struct parsing); a non-iOS host can fill it from GC.GetGCMemoryInfo().

Methods

GetInfo()

Returns the current memory snapshot. Implementations must not throw (report unavailable figures as null instead), because consumers read this on hot paths. Read a specific figure via the returned struct, e.g. VhMemory.Instance.GetInfo().ProcessFootprintMb.

public override VhMemoryInfo GetInfo()

Returns

VhMemoryInfo

The snapshot, with null for each figure the platform cannot report.

Remarks

The footprint is this process's, read fresh; the total is the device's, read once; the used memory is not read.

Install()

Installs an IosMemory as Instance, unless one is already installed ("if not created"). Idempotent; call once from each process's init (the app device / the extension service). A host may override Instance afterwards.

public static void Install()

ReadRegionCensus()

Walks the task's VM regions and buckets dirty+compressed bytes by VM user tag — the ground truth for which native owner (malloc size-class, network buffers, stacks, GC maps at tag0) holds the footprint. Returns a single log-line payload; never throws.

public static string ReadRegionCensus()

Returns

string

The census, as one log line's payload.

Remarks

vm_region_submap_info_64 is pack(4); the offsets below (user_tag@20, resident@24, swapped@32, dirtied@36, is_submap@48) were verified on-device (iPhone 11, arm64, 16 KB pages) in the 2026-07 diagnostic runs. infoCnt 19 = V2 count; falls back to 16 (V0) for older kernels.

TryRead(out FootprintInfo)

Reads a fresh phys_footprint snapshot. Returns false if the mach call fails.

public static bool TryRead(out IosMemory.FootprintInfo info)

Parameters

info IosMemory.FootprintInfo

The reading, or the default where the call fails.

Returns

bool

true if the call succeeded; otherwise, false.

TryReadAvailableMemory()

Bytes this process can still allocate before jetsam (os_proc_available_memory). -1 on failure; 0 can mean either "no budget applies" or "budget exhausted" — read it together with the footprint.

public static long TryReadAvailableMemory()

Returns

long

The bytes, or -1 where they cannot be read.

TryReadBootTimeUtc()

Device boot time (UTC) from kern.boottime. Newer than a log line = the device rebooted.

public static DateTime? TryReadBootTimeUtc()

Returns

DateTime?

The boot time, or null where it cannot be read.

TryReadFileDescriptorCount()

Returns the number of open process file descriptors, including sockets.

public static int TryReadFileDescriptorCount()

Returns

int

The count, or -1 where it cannot be read.

TryReadFileDescriptorSummary()

Buckets the open file descriptors by type (sock/vnode/kqueue/pipe/...), highest count first. Names a fd leak's owner class at a glance (e.g. leaked SQLite connections are vnodes, leaked sockets are sock). Returns "?" on failure.

public static string TryReadFileDescriptorSummary()

Returns

string

The summary, or ? where it cannot be read.