Skip to main content

Overview

gopsutil is designed to work across multiple platforms with a consistent API. However, different operating systems provide unique information that doesn’t exist on other platforms. The Ex struct feature, introduced in v4.24.5, provides access to this platform-specific information.
Ex structs are platform-specific types that extend the standard gopsutil API with OS-specific fields and methods.

Design Philosophy

The Ex struct system addresses a fundamental challenge in cross-platform system monitoring:

Common API

Standard functions like mem.VirtualMemory() work everywhere with consistent fields

Platform Extensions

Ex structs provide additional platform-specific information without breaking compatibility

Why Ex Structs?

  1. Clear Intent: Using Ex structs explicitly indicates platform-specific code
  2. Type Safety: Different platforms have different Ex types (ExLinux, ExWindows, etc.)
  3. Future Growth: New platform-specific features can be added without breaking changes
  4. Backwards Compatibility: Standard API remains unchanged

Available Ex Structs

Currently, Ex structs are available in the following packages:
  • mem: Memory information (Linux, Windows)
  • sensors: Temperature sensors (platform-specific implementations)
More Ex struct implementations may be added in future releases based on community needs.

Linux: ExLinux

Linux provides extensive memory statistics through /proc/meminfo that don’t have equivalents on other platforms.

ExLinux Memory Information

import "github.com/shirou/gopsutil/v4/mem"

// Create Linux-specific memory struct
ex := mem.NewExLinux()

// Get extended memory information
v, err := ex.VirtualMemory()
if err != nil {
    panic(err)
}

// Access Linux-specific fields
fmt.Println("Buffers:", v.Buffers)           // Buffer cache memory
fmt.Println("Cached:", v.Cached)             // Page cache memory
fmt.Println("Active:", v.Active)             // Recently used memory
fmt.Println("Inactive:", v.Inactive)         // Inactive memory
fmt.Println("Active(anon):", v.ActiveAnon)   // Anonymous active pages
fmt.Println("Inactive(anon):", v.InactiveAnon) // Anonymous inactive pages
fmt.Println("Active(file):", v.ActiveFile)   // File-backed active pages
fmt.Println("Inactive(file):", v.InactiveFile) // File-backed inactive pages
fmt.Println("Unevictable:", v.Unevictable)   // Memory that cannot be swapped
fmt.Println("Mlocked:", v.Mlocked)           // Memory locked with mlock()

Linux Memory Fields Explained

FieldDescriptionSource
BuffersMemory used for disk block buffering/proc/meminfo: Buffers
CachedMemory used for page cache/proc/meminfo: Cached
ActiveRecently accessed memory/proc/meminfo: Active
InactiveMemory not recently accessed/proc/meminfo: Inactive
ActiveAnonAnonymous memory in active state/proc/meminfo: Active(anon)
InactiveAnonAnonymous memory in inactive state/proc/meminfo: Inactive(anon)
ActiveFileFile-backed memory in active state/proc/meminfo: Active(file)
InactiveFileFile-backed memory in inactive state/proc/meminfo: Inactive(file)
UnevictableMemory that cannot be reclaimed/proc/meminfo: Unevictable
MlockedMemory locked in RAM/proc/meminfo: Mlocked

Complete Linux Example

package main

import (
    "fmt"
    "github.com/shirou/gopsutil/v4/mem"
)

func main() {
    // Standard memory info (works on all platforms)
    vmem, _ := mem.VirtualMemory()
    fmt.Printf("Total Memory: %.2f GB\n", float64(vmem.Total)/1024/1024/1024)
    fmt.Printf("Used: %.2f%%\n", vmem.UsedPercent)
    
    // Linux-specific detailed memory breakdown
    ex := mem.NewExLinux()
    exMem, err := ex.VirtualMemory()
    if err != nil {
        panic(err)
    }
    
    fmt.Println("\n=== Linux Memory Details ===")
    fmt.Printf("Buffers: %.2f GB\n", float64(exMem.Buffers)/1024/1024/1024)
    fmt.Printf("Cached: %.2f GB\n", float64(exMem.Cached)/1024/1024/1024)
    fmt.Printf("Active: %.2f GB\n", float64(exMem.Active)/1024/1024/1024)
    fmt.Printf("Inactive: %.2f GB\n", float64(exMem.Inactive)/1024/1024/1024)
    
    // Calculate reclaimable memory
    reclaimable := exMem.Cached + exMem.Buffers
    fmt.Printf("\nReclaimable (Buffers + Cached): %.2f GB\n",
        float64(reclaimable)/1024/1024/1024)
}

Windows: ExWindows

Windows uses a different memory management model compared to Unix systems. The ExWindows struct provides access to Windows virtual memory information.

ExWindows Virtual Memory

import "github.com/shirou/gopsutil/v4/mem"

// Create Windows-specific memory struct
ex := mem.NewExWindows()

// Get extended virtual memory information
v, err := ex.VirtualMemory()
if err != nil {
    panic(err)
}

// Access Windows-specific virtual memory fields
fmt.Println("Virtual Total:", v.VirtualTotal)           // Total virtual address space
fmt.Println("Virtual Available:", v.VirtualAvail)       // Available virtual memory
fmt.Println("Virtual Used:", v.VirtualUsed)             // Used virtual memory
fmt.Println("Virtual Used Percent:", v.VirtualUsedPercent) // Usage percentage

Windows Virtual Memory Explained

Windows virtual memory is different from Unix swap:
FieldDescription
VirtualTotalTotal virtual address space available to processes (typically 128 TB on 64-bit)
VirtualAvailAvailable virtual memory for allocation
VirtualUsedCurrently committed virtual memory
VirtualUsedPercentPercentage of virtual memory committed
Windows virtual memory represents the process address space, not physical memory. A 64-bit Windows system typically has 128 TB of virtual address space per process.

Complete Windows Example

package main

import (
    "fmt"
    "github.com/shirou/gopsutil/v4/mem"
)

func main() {
    // Standard memory info
    vmem, _ := mem.VirtualMemory()
    fmt.Printf("Physical Memory Total: %.2f GB\n", float64(vmem.Total)/1024/1024/1024)
    fmt.Printf("Physical Memory Used: %.2f%%\n", vmem.UsedPercent)
    
    // Windows-specific virtual memory info
    ex := mem.NewExWindows()
    exMem, err := ex.VirtualMemory()
    if err != nil {
        panic(err)
    }
    
    fmt.Println("\n=== Windows Virtual Memory ===")
    fmt.Printf("Virtual Address Space: %.2f TB\n",
        float64(exMem.VirtualTotal)/1024/1024/1024/1024)
    fmt.Printf("Virtual Available: %.2f TB\n",
        float64(exMem.VirtualAvail)/1024/1024/1024/1024)
    fmt.Printf("Virtual Used: %.2f GB\n",
        float64(exMem.VirtualUsed)/1024/1024/1024)
    fmt.Printf("Virtual Used: %.2f%%\n", exMem.VirtualUsedPercent)
}

Why No Swap on Windows?

Windows doesn’t have a traditional “swap” partition/file concept:
mem.SwapMemory() is not supported on Windows. Instead, use ExWindows.VirtualMemory() to get information about the page file and virtual memory commitment.

Cross-Platform Development

Build Tags

Use build tags to write platform-specific code:
// +build linux

package mypkg

import "github.com/shirou/gopsutil/v4/mem"

func getMemoryDetails() {
    ex := mem.NewExLinux()
    v, _ := ex.VirtualMemory()
    // Use Linux-specific fields
}
// +build windows

package mypkg

import "github.com/shirou/gopsutil/v4/mem"

func getMemoryDetails() {
    ex := mem.NewExWindows()
    v, _ := ex.VirtualMemory()
    // Use Windows-specific fields
}

Runtime Detection

import (
    "runtime"
    "github.com/shirou/gopsutil/v4/mem"
)

func getExtendedMemoryInfo() {
    switch runtime.GOOS {
    case "linux":
        ex := mem.NewExLinux()
        v, err := ex.VirtualMemory()
        if err != nil {
            return
        }
        fmt.Printf("Linux - Cached: %d\n", v.Cached)
        
    case "windows":
        ex := mem.NewExWindows()
        v, err := ex.VirtualMemory()
        if err != nil {
            return
        }
        fmt.Printf("Windows - Virtual Total: %d\n", v.VirtualTotal)
        
    default:
        // Use standard API only
        v, err := mem.VirtualMemory()
        if err != nil {
            return
        }
        fmt.Printf("Standard - Total: %d\n", v.Total)
    }
}

Interface-Based Design

type MemoryProvider interface {
    GetMemoryStats() (map[string]uint64, error)
}

type LinuxMemoryProvider struct {
    ex *mem.ExLinux
}

func (p *LinuxMemoryProvider) GetMemoryStats() (map[string]uint64, error) {
    v, err := p.ex.VirtualMemory()
    if err != nil {
        return nil, err
    }
    return map[string]uint64{
        "cached":   v.Cached,
        "buffers":  v.Buffers,
        "active":   v.Active,
        "inactive": v.Inactive,
    }, nil
}

type WindowsMemoryProvider struct {
    ex *mem.ExWindows
}

func (p *WindowsMemoryProvider) GetMemoryStats() (map[string]uint64, error) {
    v, err := p.ex.VirtualMemory()
    if err != nil {
        return nil, err
    }
    return map[string]uint64{
        "virtual_total": v.VirtualTotal,
        "virtual_avail": v.VirtualAvail,
        "virtual_used":  v.VirtualUsed,
    }, nil
}

func NewMemoryProvider() MemoryProvider {
    switch runtime.GOOS {
    case "linux":
        return &LinuxMemoryProvider{ex: mem.NewExLinux()}
    case "windows":
        return &WindowsMemoryProvider{ex: mem.NewExWindows()}
    default:
        return nil
    }
}

Best Practices

1. Check Platform Before Using Ex Structs

if runtime.GOOS != "linux" {
    log.Println("ExLinux only works on Linux")
    return
}

ex := mem.NewExLinux()

2. Fallback to Standard API

func getCachedMemory() uint64 {
    if runtime.GOOS == "linux" {
        ex := mem.NewExLinux()
        v, err := ex.VirtualMemory()
        if err == nil {
            return v.Cached
        }
    }
    
    // Fallback: not available on this platform
    return 0
}

3. Document Platform Requirements

// GetLinuxMemoryDetails returns detailed Linux memory statistics.
// This function only works on Linux and will return an error on other platforms.
func GetLinuxMemoryDetails() (*LinuxMemoryStats, error) {
    if runtime.GOOS != "linux" {
        return nil, errors.New("this function only works on Linux")
    }
    
    ex := mem.NewExLinux()
    v, err := ex.VirtualMemory()
    // ...
}

4. Use Context for Cancellation

import "context"

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

// Ex structs support context (if available)
ex := mem.NewExLinux()
v, err := ex.VirtualMemoryWithContext(ctx)

Future Extensions

The Ex struct pattern may be extended to other packages in future releases:

Potential Areas

  • CPU: Frequency scaling, power states
  • Disk: Filesystem-specific statistics
  • Network: Protocol-specific counters
  • Process: Platform-specific attributes

Request Features

If you need platform-specific information, open an issue on GitHub describing your use case

Migration from v3

Ex structs are a new feature in v4.24.5. There’s no equivalent in v3.
If you previously accessed platform-specific fields directly, you now need to use Ex structs:
// v3 and earlier (fields may not exist)
v, _ := mem.VirtualMemory()
// v.Cached may or may not exist depending on platform

// v4.24.5+ (explicit platform-specific access)
if runtime.GOOS == "linux" {
    ex := mem.NewExLinux()
    v, _ := ex.VirtualMemory()
    // v.Cached is guaranteed to exist on Linux
}

Linux Support

Learn about Linux-specific features

Windows Support

Explore Windows platform capabilities

Platform Overview

Compare all platform support

v4 Migration

Full v4 migration guide

Build docs developers (and LLMs) love