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?
Clear Intent : Using Ex structs explicitly indicates platform-specific code
Type Safety : Different platforms have different Ex types (ExLinux, ExWindows, etc.)
Future Growth : New platform-specific features can be added without breaking changes
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.
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
Field Description Source BuffersMemory used for disk block buffering /proc/meminfo: BuffersCachedMemory used for page cache /proc/meminfo: CachedActiveRecently accessed memory /proc/meminfo: ActiveInactiveMemory not recently accessed /proc/meminfo: InactiveActiveAnonAnonymous 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: UnevictableMlockedMemory 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 ( " \n Reclaimable (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:
Field Description 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.
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
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
}
// 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