Argo is a high-performance memory arena library for Go that provides GC-free memory management specifically designed for CGO interoperability. It eliminates garbage collection overhead by managing memory outside of Go's heap using C's malloc/free.
- π₯ GC-Free Memory Management - Zero garbage collection overhead
- β‘ High Performance - Significant speedup for CGO operations
- π‘οΈ Memory Safety - Automatic cleanup with finalizers
- π CGO Optimized - Seamless C/Go data exchange
- π Built-in Statistics - Memory usage monitoring
- π― Type-Safe Handles - Generic array handling with type safety
- π§΅ Thread-Safe - Concurrent access protection
- βοΈ Context Support - Timeout and cancellation support
- π§© Modular Design - Clean separation between core library and examples
go get github.com/devicemxl/argo- Go 1.20 or later
- CGO enabled (
CGO_ENABLED=1) - C compiler (gcc, clang, etc.)
package main
import (
"fmt"
"github.com/devicemxl/argo"
)
func main() {
// Simple arena usage with automatic cleanup
result := argo.WithArena(func(arena *argo.Arena) string {
// Create C string in GC-free memory
cstr := arena.CString("Hello, World!")
// Convert back to Go string
return arena.GoString(cstr)
})
fmt.Println(result) // Output: Hello, World!
}/*
#include <string.h>
#include <stdlib.h>
char* process_string(const char* input, int multiplier) {
size_t len = strlen(input);
char* result = malloc(len * multiplier + 1);
result[0] = '\0';
for (int i = 0; i < multiplier; i++) {
strcat(result, input);
}
return result;
}
*/
import "C"
import "unsafe"
func ProcessWithCGO() {
result := argo.WithArena(func(arena *argo.Arena) string {
// Use UnsafeCString for CGO compatibility
cstr := arena.UnsafeCString("Go+C ")
// Call C function
cresult := C.process_string((*C.char)(cstr), 3)
defer C.free(unsafe.Pointer(cresult))
// Convert C result back to Go string
return C.GoString(cresult)
})
fmt.Println(result) // Output: Go+C Go+C Go+C
}Creates a new memory arena with optional configuration.
arena := argo.NewArena()
defer arena.Free() // Always free when doneAllocates aligned memory within the arena.
ptr := arena.Alloc(1024, 8) // 1KB with 8-byte alignmentFrees all arena memory. Must be called explicitly.
arena.Free() // Releases all allocated memoryConverts Go string to null-terminated C string in arena memory.
cstr := arena.CString("Hello") // Managed by arenaReturns unsafe.Pointer for CGO compatibility across packages.
cstr := arena.UnsafeCString("Hello") // For CGO interopConverts C string to Go string.
goStr := arena.GoString(cstr)Copies C data to Go byte slice.
bytes := arena.GoBytes(cptr, 100)Converts Go string slice to C string array.
cstrArray := arena.CStringArray([]string{"hello", "world"})Converts C string array back to Go string slice.
goStrings := arena.GoStringArray(cstrArray, 2)Creates a type-safe handle for array data in arena memory.
numbers := []int32{1, 2, 3, 4, 5}
handle := argo.NewHandle(arena, numbers)
// Get C pointer for CGO
cptr := (*C.int)(handle.Ptr())
// Get Go slice back
result := handle.Get()Convenience function with automatic cleanup.
result := argo.WithArena(func(arena *argo.Arena) string {
// Your code here - arena is automatically freed
return "result"
})Arena with context support for timeouts and cancellation.
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
result := argo.WithArenaContext(ctx, func(ctx context.Context, arena *argo.Arena) bool {
// Long-running operation with timeout support
return processData(ctx, arena)
})Prints detailed memory usage statistics.
arena.PrintArenaStats()
// Output: Arena Stats: Chunks: 2, Total: 16384 bytes, Used: 8192 bytes// Custom arena options (extend as needed)
func WithInitialSize(size uintptr) argo.ArenaOption {
return func(a *argo.Arena) {
// Custom initialization logic
}
}
arena := argo.NewArena(WithInitialSize(1024*1024)) // 1MB initial
defer arena.Free()// Arena is thread-safe for concurrent access
arena := argo.NewArena()
defer arena.Free()
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
data := fmt.Sprintf("worker-%d", id)
cstr := arena.CString(data) // Safe concurrent access
// Process data...
}(i)
}
wg.Wait()The example/ directory contains a comprehensive demonstration of Argo's capabilities with various C utility functions:
# Build and run the full example
make run
# Or manually:
cd example && go run .- String Processing: Repetition, concatenation, case conversion
- Array Operations: In-place modification, aggregation, sorting
- Data Generation: Sequences, random arrays, pattern data
- Mathematical Functions: Fast power, Newton's square root, factorial
- Cryptography: Caesar cipher encryption/decryption
- Validation: Email and URL format checking
- Data Conversion: Hex encoding/decoding, hash functions
- Bit Operations: Bit counting, bit reversal
- Performance Comparison: GC vs GC-free benchmarks
example/
βββ main.go # Main demonstration program
βββ argoFun.go # CGO wrapper functions for C utilities
βββ cgo_utils.c # C implementation of utility functions
βββ cgo_utils.h # C header declarations
Traditional CGO (with GC): 2.45ms
Argo Arena (GC-free): 0.87ms
Performance improvement: 2.82x faster
Memory allocations: 95% reduction
GC pressure: Eliminated
β Perfect for:
- Heavy CGO operations
- Large data processing with C libraries
- High-frequency C/Go data exchange
- Applications requiring predictable latency
- Embedded systems with limited memory
β Not recommended for:
- Short-lived, small allocations
// Finalizer ensures cleanup even if Free() is forgotten
arena := argo.NewArena()
// Even without explicit Free(), finalizer will clean up
// But explicit Free() is still recommended!// β
GOOD: Use WithArena for automatic cleanup
result := argo.WithArena(func(arena *argo.Arena) Data {
return processData(arena)
})
// β
GOOD: Explicit cleanup
arena := argo.NewArena()
defer arena.Free()
data := processData(arena)
// β BAD: Forgetting to free
arena := argo.NewArena()
data := processData(arena)
// Memory leak! (though finalizer will eventually clean up)# Ensure CGO is enabled
export CGO_ENABLED=1
# Build the project
make build
# Run examples
make run
# Run tests
make test
# Run benchmarks
make benchmarkmake build # Build the example
make run # Build and run examples
make test # Run tests for main library
make test-example # Run tests for example
make test-module # Test that argo.go compiles independently
make benchmark # Run benchmarks
make clean # Remove generated files
make debug # Build with debug symbols
make release # Build with optimizations
make check # Verify all files are present
make info # Show system information
make help # Show all available targetsargo/
βββ argo.go # Core arena implementation (CGO-free)
βββ example/ # Complete usage examples
β βββ main.go # Example demonstrations
β βββ argoFun.go # CGO wrapper functions
β βββ cgo_utils.c # C utility implementations
β βββ cgo_utils.h # C header declarations
βββ Makefile # Build configuration
βββ go.mod # Go module definition
βββ README.md # This documentation
make debug # Build with debug symbols// Pattern 1: Batch processing
argo.WithArena(func(arena *argo.Arena) {
for _, item := range largeDataset {
processItem(arena, item)
}
// All memory freed automatically
})
// Pattern 2: Long-lived arena
arena := argo.NewArena()
defer arena.Free()
for {
if shouldExit {
break
}
processRequest(arena)
// Memory accumulates until arena.Free()
}func TestArenaIntegration(t *testing.T) {
result := argo.WithArena(func(arena *argo.Arena) string {
return arena.GoString(arena.CString("test"))
})
if result != "test" {
t.Errorf("Expected 'test', got '%s'", result)
}
}func TestCGOIntegration(t *testing.T) {
// Your CGO function tests here
result := argo.WithArena(func(arena *argo.Arena) bool {
// Test your specific CGO functions
return testYourCGOFunction(arena)
})
if !result {
t.Error("CGO integration test failed")
}
}- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Run tests (
make test && make test-example) - Commit your changes (
git commit -am 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- Inspired by Go's experimental arena proposal
- Built for high-performance CGO applications
- Designed with memory safety and modularity in mind
- π Issues: GitHub Issues
- π Documentation: GoDoc
- π¬ Discussions: GitHub Discussions
Made with β€οΈ for the Go + CGO community