structoptimizer

module
v1.9.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 6, 2026 License: MIT

README ΒΆ

StructOptimizer

Test Release Go Report Card License Go Version

Optimize Go struct field alignment to reduce memory padding and save memory

δΈ­ζ–‡ζ–‡ζ‘£ β€’ English


πŸ“– Overview

StructOptimizer is a powerful Go struct memory alignment optimization tool. It reduces memory padding by intelligently rearranging struct field order, helping you save memory in large-scale Go applications.

Why Memory Optimization Matters

In large Go projects, poorly aligned struct fields can waste significant memory due to padding. Consider this example:

// ❌ Before Optimization (32 bytes, 15 bytes wasted)
type User struct {
    Name    string  // 16 bytes
    Age     uint8   // 1 byte
    Active  bool    // 1 byte
    Balance float64 // 8 bytes
    ID      int64   // 8 bytes
    // 14 bytes padding inserted by compiler
}

// βœ… After Optimization (24 bytes, saved 8 bytes = 25%)
type User struct {
    Balance float64 // 8 bytes
    ID      int64   // 8 bytes
    Name    string  // 16 bytes
    Age     uint8   // 1 byte
    Active  bool    // 1 byte
    // 6 bytes padding only
}

At scale: If you have 1 million User instances, that's 8 MB saved just from one struct!


✨ Key Features

Core Capabilities
Feature Description
πŸ”§ Field Reordering Automatically rearrange struct fields for optimal alignment
πŸ“¦ Nested Struct Support Handle deeply nested struct hierarchies (up to 50 levels)
πŸ”— Cross-Package Optimization Optimize structs referenced across multiple packages
🎯 Smart Deduplication Each struct optimized only once
πŸ“Š Detailed Reports Generate TXT/MD/HTML reports with before/after comparisons
Advanced Features
Feature Description
πŸ’Ύ Auto Backup Create timestamped backups before modifying source files
⏭️ Flexible Skipping Skip directories, files, or specific structs by name/method
πŸ—οΈ Dual Project Support Works with both Go Modules and GOPATH+vendor projects
πŸ›‘οΈ Safe Optimization Only reorder when memory savings are guaranteed
πŸ“ Reserved Fields Keep specific fields (e.g., reserved, padding) at the end
πŸ” Verbose Logging Multiple verbosity levels (-v, -vv, -vvv) for debugging

πŸš€ Quick Start

Installation
# macOS / Linux - auto-detects package manager or falls back to direct download
curl -fsSL https://raw.githubusercontent.com/gamelife1314/structoptimizer/main/install.sh | bash

# Install a specific version
curl -fsSL https://raw.githubusercontent.com/gamelife1314/structoptimizer/main/install.sh | VERSION=v1.9.0 bash

# Custom install directory
curl -fsSL https://raw.githubusercontent.com/gamelife1314/structoptimizer/main/install.sh | INSTALL_DIR=/usr/bin bash
Option 2: Homebrew (macOS / Linux)
brew tap gamelife1314/structoptimizer
brew install structoptimizer
Option 3: Go Install
go install github.com/gamelife1314/structoptimizer/cmd/structoptimizer@latest
Option 4: APT / YUM (Linux)
# Debian / Ubuntu (APT) - full package manager integration
echo "deb [trusted=yes] https://gamelife1314.github.io/structoptimizer/apt stable main" \
  | sudo tee /etc/apt/sources.list.d/structoptimizer.list
sudo apt update && sudo apt install structoptimizer

# RHEL / Fedora (YUM/DNF) - full package manager integration
sudo tee /etc/yum.repos.d/structoptimizer.repo <<EOF
[structoptimizer]
name=StructOptimizer
baseurl=https://gamelife1314.github.io/structoptimizer/yum
enabled=1
gpgcheck=0
EOF
sudo yum install structoptimizer     # or: sudo dnf install structoptimizer
Option 5: Manual Download
# macOS (Apple Silicon)
curl -LO https://github.com/gamelife1314/structoptimizer/releases/latest/download/structoptimizer-darwin-arm64.tar.gz
tar -xzf structoptimizer-darwin-arm64.tar.gz && sudo mv structoptimizer /usr/local/bin/

# macOS (Intel)
curl -LO https://github.com/gamelife1314/structoptimizer/releases/latest/download/structoptimizer-darwin-amd64.tar.gz
tar -xzf structoptimizer-darwin-amd64.tar.gz && sudo mv structoptimizer /usr/local/bin/

# Linux (amd64)
curl -LO https://github.com/gamelife1314/structoptimizer/releases/latest/download/structoptimizer-linux-amd64.tar.gz
tar -xzf structoptimizer-linux-amd64.tar.gz && sudo mv structoptimizer /usr/local/bin/

# Linux (arm64)
curl -LO https://github.com/gamelife1314/structoptimizer/releases/latest/download/structoptimizer-linux-arm64.tar.gz
tar -xzf structoptimizer-linux-arm64.tar.gz && sudo mv structoptimizer /usr/local/bin/

# Windows
curl -LO https://github.com/gamelife1314/structoptimizer/releases/latest/download/structoptimizer-windows-amd64.zip
# Extract and add to PATH
Option 6: Build from Source
git clone https://github.com/gamelife1314/structoptimizer.git
cd structoptimizer
go build -o structoptimizer ./cmd/structoptimizer
Basic Usage

Step 1: Analyze without modifying (generate report only)

# Optimize a specific struct
structoptimizer -struct=example.com/mypkg.User /path/to/project

# Optimize all structs in a package
structoptimizer -package=example.com/mypkg /path/to/project

Step 2: Review the generated report (report.md)

Step 3: Apply optimizations (with automatic backup)

structoptimizer -package=example.com/mypkg -write -backup /path/to/project

πŸ“š Usage Guide

Command Line Options
Usage: structoptimizer [options] <project_directory>

Options:
  -struct string        Struct name (format: package.path.StructName)
  -package string       Package path (mutually exclusive with -struct)
  -write                Write changes to source files
  -backup               Backup source files before modification (default: true)
  -output string        Report output path
  -format string        Report format: txt, md, html (default: md)
  -skip-dirs string     Skip directories (wildcard support, comma-separated)
  -skip-files string    Skip files (wildcard support, comma-separated)
  -skip-by-methods string  Skip structs with these methods (comma-separated)
  -skip-by-names string    Skip structs with these names (comma-separated)
  -reserved-fields string  Fields to keep at the end (comma-separated)
  -sort-same-size       Reorder fields even when size is the same
  -max-depth int        Maximum recursion depth (default: 50)
  -timeout int          Timeout in seconds (default: 1200)
  -prj-type string      Project type: gomod, gopath (default: gomod)
  -pkg-scope string     Package scope limit (required for GOPATH mode)
  -pkg-limit int        Package concurrency limit (default: 4)
  -gopath string        GOPATH path (optional, uses env if not set)
  -recursive            Recursively scan all sub-packages (-package mode only)
  -lang string          Report language: zh, en (default: zh)
  -allow-external-pkgs  Allow scanning cross-package structs (including vendor, default: false)
  -v, -vv, -vvv         Verbose output levels
  -version              Show version information
Common Scenarios
1. Analyze Single Struct
# Generate report without modifying source
structoptimizer -struct=github.com/myapp/models.User ./myproject

# Output: report.md
2. Optimize Entire Package
# Optimize all structs in the models package
structoptimizer -package=github.com/myapp/models -write -backup ./myproject
2.1. Recursive Package Scanning (NEW)
# Scan package and ALL its sub-packages recursively
structoptimizer -package=github.com/myapp/pkg -recursive -write -backup ./myproject

# Example output:
# - Scans github.com/myapp/pkg
# - Scans github.com/myapp/pkg/apis
# - Scans github.com/myapp/pkg/models
# - Scans github.com/myapp/pkg/utils
# - Automatically skips vendor and standard library

How it works:

  • Uses BFS (Breadth-First Search) to traverse package dependency graph
  • Starts from root package, discovers all imported sub-packages
  • Automatically skips standard library and vendor packages
  • Only scans sub-packages under the root package path

Use cases:

  • Large projects with many sub-packages (50+ packages)
  • Deeply nested package hierarchies (10+ levels)
  • GOPATH+vendor projects
  • When you want to optimize entire module at once
2.2. GOPATH Project: -pkg-scope Parameter (IMPORTANT)

For GOPATH mode only, the -pkg-scope parameter is REQUIRED:

# GOPATH project - MUST specify -pkg-scope
structoptimizer -prj-type=gopath \
  -package=github.com/myproject/pkg \
  -pkg-scope=github.com/myproject \
  -recursive -write -backup

What is -pkg-scope?

  • Limits the analysis scope to packages under the specified path prefix
  • Prevents analyzing unrelated projects in your GOPATH
  • Works with -recursive to discover all sub-packages within scope

How to set -pkg-scope:

  1. Identify your project's module path (e.g., github.com/myproject)
  2. Use the root path as scope (e.g., -pkg-scope=github.com/myproject)
  3. All packages starting with this prefix will be included

Example:

# Project structure:
# $GOPATH/src/github.com/myproject/
# β”œβ”€β”€ pkg/
# β”‚   β”œβ”€β”€ apis/
# β”‚   β”œβ”€β”€ models/
# β”‚   └── utils/
# └── vendor/

# Correct usage:
structoptimizer -prj-type=gopath \
  -package=github.com/myproject/pkg \
  -pkg-scope=github.com/myproject \
  -recursive

# This will scan:
# βœ… github.com/myproject/pkg
# βœ… github.com/myproject/pkg/apis
# βœ… github.com/myproject/pkg/models
# βœ… github.com/myproject/pkg/utils
# ❌ github.com/otherproject/pkg (outside scope)
# ❌ vendor/* (automatically skipped)

Common mistakes:

# ❌ Missing -pkg-scope (will fail in GOPATH mode)
structoptimizer -prj-type=gopath -package=github.com/myproject/pkg

# ❌ Too narrow scope (won't find sub-packages)
structoptimizer -prj-type=gopath \
  -package=github.com/myproject/pkg \
  -pkg-scope=github.com/myproject/pkg  # Too specific!

# βœ… Correct: use project root as scope
structoptimizer -prj-type=gopath \
  -package=github.com/myproject/pkg \
  -pkg-scope=github.com/myproject

When to use:

  • Legacy GOPATH projects (pre-Go Modules)
  • Projects using vendor directory
  • Multiple projects in same GOPATH workspace
2.3. Allow Cross-Package Scanning (-allow-external-pkgs) (NEW)

By default, StructOptimizer skips structs outside the -pkg-scope range and vendor packages. Use -allow-external-pkgs to include them:

# GOPATH project - include vendor packages in analysis
structoptimizer -prj-type=gopath \
  -package=github.com/myproject/pkg \
  -pkg-scope=github.com/myproject \
  -allow-external-pkgs \
  -recursive

# This will now scan:
# βœ… github.com/myproject/pkg
# βœ… github.com/myproject/pkg/apis
# βœ… vendor/github.com/external/lib  (previously skipped)
# βœ… github.com/otherproject/pkg    (previously skipped, if outside scope)
# ❌ Go standard library (always skipped)

Use cases:

  • Need to optimize structs that reference types in vendor directories
  • GOPATH projects where vendor packages contain structs worth optimizing
  • When -pkg-scope is too restrictive but you still want package isolation
3. Skip Third-Party Code
# Skip vendor and generated code
structoptimizer -package=github.com/myapp/models \
  -skip-dirs="vendor,generated_*,mocks" \
  -skip-files="*_test.go,*_pb.go" \
  -write -backup ./myproject
4. Preserve API Compatibility
# Keep certain fields at the end for serialization compatibility
structoptimizer -struct=github.com/myapp/models.Config \
  -reserved-fields="XXX_sizecache,XXX_unrecognized,reserved" \
  -write -backup ./myproject
5. Skip Structs with Specific Methods
# Skip structs that have MarshalJSON method (may have custom serialization)
structoptimizer -package=github.com/myapp/models \
  -skip-by-methods="MarshalJSON,UnmarshalJSON,Encode,Decode" \
  -write -backup ./myproject
6. GOPATH Project Support
# For legacy GOPATH projects
structoptimizer -prj-type=gopath \
  -package=github.com/myproject/models \
  -pkg-scope=github.com/myproject \
  -write -backup

πŸ“Š Report Example

╔════════════════════════════════════════════════════════════════════════════════╗
β•‘                     StructOptimizer Optimization Report                        β•‘
β•‘  Version v1.7.6                                                                β•‘
β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
Generated: 2026-04-18 14:41:15

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  πŸ“Š Summary                                                                    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Total Structs Processed:  156                                                 β”‚
β”‚  βœ… Optimized:              43                                                 β”‚
β”‚  ⏭️  Skipped:               113                                                β”‚
β”‚  πŸ’Ύ Memory Saved:           2,847 bytes                                        β”‚
β”‚  πŸ“ˆ Total Size Before:      45,678 bytes                                       β”‚
β”‚  πŸ“‰ Total Size After:       42,831 bytes                                       β”‚
β”‚  πŸ“Š Overall Optimization:   6.2%                                               β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

✏️  Optimized Structs (43)
─────────────────────────────────────────────────────────────────────────────────

πŸ“¦ github.com/myapp/models.User
   πŸ“ File: models/user.go
   πŸ“ Size: 32 bytes β†’ 24 bytes (saved: 8 bytes, 25.0%)
   
   Field Order Comparison:
   β”Œβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   β”‚ #  β”‚ Before              β”‚ After               β”‚ Size     β”‚ Changed  β”‚
   β”œβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
   β”‚ 1  β”‚ Name: string        β”‚ Balance: float64    β”‚ 16 β†’ 8   β”‚ βœ“        β”‚
   β”‚ 2  β”‚ Age: uint8          β”‚ ID: int64           β”‚ 1 β†’ 8    β”‚ βœ“        β”‚
   β”‚ 3  β”‚ Active: bool        β”‚ Name: string        β”‚ 1 β†’ 16   β”‚ βœ“        β”‚
   β”‚ 4  β”‚ Balance: float64    β”‚ Age: uint8          β”‚ 8 β†’ 1    β”‚ βœ“        β”‚
   β”‚ 5  β”‚ ID: int64           β”‚ Active: bool        β”‚ 8 β†’ 1    β”‚ βœ“        β”‚
   β””β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ—οΈ How It Works

Two-Phase Optimization Architecture
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Phase 1: Collection (No Package Loading)                                   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  β€’ Parse source files using AST                                             β”‚
β”‚  β€’ Identify all structs and nested relationships                            β”‚
β”‚  β€’ Organize by dependency level (0 = leaf, N = root)                        β”‚
β”‚  β€’ Skip vendor, standard library, third-party packages                      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                    ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Phase 2: Parallel Optimization (On-Demand Package Loading)                 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  β€’ Process from leaf level upward (ensures nested structs optimized first)  β”‚
β”‚  β€’ Load packages only when needed                                           β”‚
β”‚  β€’ Concurrent processing with configurable limits                           β”‚
β”‚  β€’ Automatic garbage collection between levels                              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Optimization Algorithm
  1. Field Analysis: Extract type, size, and alignment for each field
  2. Size Calculation: Compute original struct size with padding
  3. Optimal Ordering: Sort fields by size (largest to smallest)
  4. Validation: Only apply if new size < original size
  5. Source Rewrite: Update source file with new field order

🎯 Best Practices

When to Use

βœ… Recommended:

  • Large structs (>32 bytes) with mixed field types
  • High-volume data structures (millions of instances)
  • Memory-constrained environments
  • Long-running services

⚠️ Use with Caution:

  • Structs with custom serialization (use -reserved-fields)
  • Structs shared via FFI or C bindings
  • Structs where field order affects external APIs
Performance Impact
Scenario Memory Savings Performance Change
Small structs (<16 bytes) Minimal Negligible
Medium structs (16-64 bytes) 10-25% Improved cache locality
Large structs (>64 bytes) 20-40% Significant improvement
Deeply nested structs Cumulative Better overall

πŸ”§ Troubleshooting

Common Issues

Issue: "GOPATH mode requires -pkg-scope parameter"

Solution: Specify your project's package prefix:

structoptimizer -prj-type=gopath -pkg-scope=github.com/myproject ...

Issue: "Optimization timeout after 1200 seconds"

Solution: Increase timeout for large projects:

structoptimizer -timeout=3600 ...  # 1 hour

Issue: "Multiple packages found"

Solution: Ensure you're running from the project root with go.mod:

cd /path/to/project  # Directory containing go.mod
structoptimizer -package=github.com/myapp/models

🀝 Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request
Development Setup
git clone https://github.com/gamelife1314/structoptimizer.git
cd structoptimizer
go test ./...  # Run all tests
go build ./cmd/structoptimizer

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.


πŸ™ Acknowledgments


Made with Go | Report Bug | Request Feature

Directories ΒΆ

Path Synopsis
cmd
structoptimizer command
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL