Skip to main content

MemInfo

Struct MemInfo 

Source
pub struct MemInfo {
Show 27 fields pub total: u64, pub available: u64, pub used: u64, pub free: u64, pub classes: Vec<MemoryClass>, pub buffers: u64, pub cached: u64, pub sreclaimable: u64, pub shmem: u64, pub wired: u64, pub compressed: u64, pub active: u64, pub inactive: u64, pub purgeable: u64, pub speculative: u64, pub zswap: u64, pub zswapped: u64, pub zswap_max: u64, pub huge_pages_total: u64, pub huge_pages_free: u64, pub huge_pages_rsvd: u64, pub huge_pages_surplus: u64, pub huge_page_size: u64, pub laundry: u64, pub file_cache: u64, pub managed_pages: u64, pub internal: u64,
}
Expand description

The memory breakdown a platform reports.

Every backend fills in total and classes, then calls finish_linux or finish_darwin exactly once to derive used/available.

The classes are the authority on what counts as used: finish_* only sums the flags. This matters because the platforms genuinely disagree, and every attempt to hardcode a formula produced a number that contradicted either the class sum or the operating system (docs/PORTABILITY.md).

Fields§

§total: u64§available: u64

Memory that can be handed to a new allocation, including reclaimable cache. Derived by the finish_* methods.

§used: u64

Derived: the sum of every class flagged counts_as_used.

§free: u64

Free pages. Not a class of its own on macOS, where free is tiny and the page cache holds the slack.

§classes: Vec<MemoryClass>

The ordered class list. Order is the bar-segment order.

§buffers: u64§cached: u64§sreclaimable: u64§shmem: u64§wired: u64§compressed: u64§active: u64§inactive: u64§purgeable: u64§speculative: u64§zswap: u64

Bytes currently held in the zswap pool (Meminfo: Zswap).

Not part of the memory bar: zswap pages are anonymous pages that have been compressed, so they are already counted in used. Reporting them again would double-count. They get their own meter instead.

§zswapped: u64

Bytes swapped out to zswap over the machine’s lifetime (Zswapped).

§zswap_max: u64

The zswap pool’s ceiling, from /sys/module/zswap/parameters/max_pool_percent times physical memory. 0 when the parameter is unreadable.

§huge_pages_total: u64

Huge page counters, in pages (Meminfo: HugePages_*).

§huge_pages_free: u64§huge_pages_rsvd: u64§huge_pages_surplus: u64§huge_page_size: u64

Bytes per huge page (Hugepagesize), 0 when huge pages are disabled.

§laundry: u64

Pages that are dirty and queued for writeback (v_laundry_count).

FreeBSD counts these separately from active and inactive, and they cannot be reused without a write first, so they belong in used rather than in cache.

§file_cache: u64

The page cache (v_cache_count), in bytes rather than pages.

Modern FreeBSD folds the unified buffer cache into the inactive queue and reports 0 here; it is kept because older kernels and vfs.bufspace still populate it, and silently dropping it would understate reclaimable memory on exactly those systems.

§managed_pages: u64

v_page_count, the number of pages the VM subsystem manages.

Used as the denominator for the partition check: active + inactive + laundry + wired + free must equal it, which is what makes the bar segments add up to physical memory.

§internal: u64

internal_page_count: anonymous pages, the “by backing store” family.

macOS reports memory twice over, once by usage (active, inactive, …) and once by backing store (internal, external). Only this one is needed for accounting, because internal is exactly active + inactive + speculative - external and therefore counts each anonymous page once instead of re-adding overlapping usage classes.

Implementations§

Source§

impl MemInfo

Source

pub fn used_from_classes(&self) -> u64

Sum the classes tagged counts_as_used.

Source

pub fn cache_from_classes(&self) -> u64

Sum the classes tagged counts_as_cache.

Source

pub fn finish_linux(&mut self)

Linux/GNU free accounting, matching linux/LinuxMachine.c.

used = total - free - cached - sreclaimable - buffers, with shmem subtracted from the cached total first so it is not counted twice. available is MemAvailable clamped to total, falling back to free on kernels older than 3.14 that do not provide it.

Do not try to make used + available == total here: they measure different things, and forcing it clamps MemAvailable down to total - used, which is a much smaller (wrong) number.

Source

pub fn finish_darwin(&mut self)

macOS accounting, matching htop 3.4 and later.

used = (internal - purgeable) + wired + compressed

htop 3.4.1 (darwin/Platform.c, Platform_setMemoryValues) says it the long way round:

natural_t used = vm->active_count + vm->inactive_count +
                 vm->speculative_count + vm->wire_count +
                 vm->compressor_page_count - vm->purgeable_count -
                 vm->external_page_count;
mtr->values[MEMORY_METER_USED]       = (double)(used - vm->compressor_page_count) * page_K;
mtr->values[MEMORY_METER_COMPRESSED] = (double)vm->compressor_page_count * page_K;

and MemoryMeter_updateValues prints USED + COMPRESSED. That sum is internal + wired + compressed, because internal_page_count is active + inactive + speculative - external. htop main (3.6-dev) states the same figure directly, as a class list marked countsAsUsed: wired, internal - purgeable, compressed. One formula therefore matches both, and it matches Activity Monitor and top as well.

Consequences, all intentional:

  • The compressor is counted as used. On a Mac that has been running a while it is the largest single term — 7 GB on a 16 GB machine is normal — and leaving it out made gander report ~5 GB where htop reported ~13 GB.
  • inactive and speculative are not added on top. They are part of internal (or are file cache), so adding them double-counts; that was the other shipped mistake, and it is why the by-backing-store counter is used here instead of the by-usage ones.
  • free is vm_stat’s own free count. Deriving it as total - used - cache is what made the bar claim 7.8 GB free on a machine with 0.3 GB free: the compressor pages that used omitted fell through into the free segment.
  • available = total - used, so the two figures partition memory exactly, and so do the bar segments.

The old htop-3.3.0 formula (used = active + wired, compressor ignored) is gone: it was the reason the meter disagreed with every other tool by the size of the compressor.

Source

pub fn finish_freebsd(&mut self)

FreeBSD accounting.

FreeBSD’s VM keeps five mutually exclusive page queues, so the model is a partition rather than a formula:

used      = active + wired + laundry
cache     = inactive + page cache
available = free + cache

Every page is in exactly one queue (v_page_count is their sum), which is why the bar segments can be checked against physical memory the way macOS’s can. laundry counts as used because those pages cannot be reused until their write completes — the same reasoning that puts macOS’s compressor in used.

free is the kernel’s own free count, never total - used: deriving it is what made the macOS bar claim 7.8 GB free on a machine with 0.3 GB.

Source

pub fn huge_used_bytes(&self) -> u64

Huge pages in use, in bytes.

total - free rather than total - free - rsvd: reserved pages are already committed to a process that has not faulted them in yet, so a free figure that includes them overstates what is actually available. htop prints used/total with the same subtraction.

Source

pub fn huge_total_bytes(&self) -> u64

Source

pub fn huge_pages_configured(&self) -> bool

Whether the kernel has huge pages configured at all.

A machine with HugePages_Total of 0 has the feature compiled in but nothing reserved; a meter for it would be a permanent empty bar, so the meter says n/a here instead. Same reasoning as DiskIO on macOS.

Source

pub fn compute_used(&mut self)

Backwards-compatible alias used by the Linux parser.

Source

pub fn is_consistent(&self) -> bool

Whether every derived figure is within physical bounds.

Source

pub fn is_exactly_partitioned(&self) -> bool

Stronger check for platforms that derive available from used.

Trait Implementations§

Source§

impl Clone for MemInfo

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for MemInfo

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for MemInfo

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.