This guide provides detailed information about optimizing JSON performance in PivotPHP Core v1.1.1 and later.
JSON pooling is a performance optimization technique that reuses buffer objects to reduce memory allocation overhead and garbage collection pressure.
JSON pooling provides the most benefit in these scenarios:
- High-Frequency Operations: APIs processing hundreds or thousands of JSON requests per second
- Medium to Large Datasets: Arrays with 10+ elements, objects with 5+ properties
- Sustained Load: Long-running applications with continuous JSON processing
- Memory-Constrained Environments: Applications where garbage collection pressure matters
For these scenarios, traditional json_encode() may be faster:
- Small Data: Simple objects with 1-3 properties
- Infrequent Operations: Applications processing <10 JSON operations per second
- Large Single Objects: Very large objects (>1MB) that don't benefit from buffer reuse
Based on comprehensive testing with PivotPHP Core v1.1.1:
| Scenario | Traditional | Pooled | Improvement |
|---|---|---|---|
| Small JSON (< 1KB) | 2.5M ops/sec | 2.5M ops/sec | 0% (fallback) |
| Medium JSON (1-10KB) | 400K ops/sec | 600K ops/sec | +50% |
| Large JSON (10-100KB) | 180K ops/sec | 300K ops/sec | +67% |
| Sustained Load (60s) | 85K ops/sec | 101K ops/sec | +19% |
| Scenario | Traditional Memory | Pooled Memory | Reduction |
|---|---|---|---|
| 10K operations | 150MB peak | 45MB peak | 70% |
| Sustained load | 200MB growing | 60MB stable | 70% |
| GC cycles | 50 collections | 15 collections | 70% |
// Optimized for 1000+ requests/second
JsonBufferPool::configure([
'max_pool_size' => 500,
'default_capacity' => 8192,
'size_categories' => [
'small' => 2048, // User profiles, small responses
'medium' => 8192, // Product lists, search results
'large' => 32768, // Detailed reports, bulk data
'xlarge' => 131072 // Export operations, large datasets
]
]);// Balanced configuration for microservices
JsonBufferPool::configure([
'max_pool_size' => 100,
'default_capacity' => 4096,
'size_categories' => [
'small' => 1024,
'medium' => 4096,
'large' => 16384,
'xlarge' => 65536
]
]);// Memory-efficient configuration for workers
JsonBufferPool::configure([
'max_pool_size' => 50,
'default_capacity' => 4096,
'size_categories' => [
'small' => 1024,
'medium' => 4096,
'large' => 16384,
'xlarge' => 65536
]
]);// Minimal configuration for development
JsonBufferPool::configure([
'max_pool_size' => 20,
'default_capacity' => 2048,
'size_categories' => [
'small' => 512,
'medium' => 2048,
'large' => 8192,
'xlarge' => 32768
]
]);Monitor these metrics to optimize pool performance:
$stats = JsonBufferPool::getStatistics();
// Efficiency metrics
$reuseRate = $stats['reuse_rate']; // Target: >80%
$totalOps = $stats['total_operations']; // Volume indicator
$currentUsage = $stats['current_usage']; // Memory usage
$peakUsage = $stats['peak_usage']; // Capacity planning
// Pool utilization
$poolSizes = $stats['pool_sizes']; // Buffer distribution| Metric | Good | Warning | Action Needed |
|---|---|---|---|
| Reuse Rate | >80% | 50-80% | <50% |
| Current Usage | <100 | 100-500 | >500 |
| Pool Growth | Stable | Slow growth | Rapid growth |
Possible Causes:
- Pool sizes too small for workload
- Data sizes don't match pool categories
- Mixed workload with varying data sizes
Solutions:
// Increase pool sizes
JsonBufferPool::configure(['max_pool_size' => 200]);
// Add intermediate size categories
JsonBufferPool::configure([
'size_categories' => [
'tiny' => 512,
'small' => 2048,
'medium' => 8192,
'large' => 32768,
'xlarge' => 131072
]
]);Possible Causes:
- Pool sizes too large
- Memory leaks in application code
- Buffers not being returned properly
Solutions:
// Reduce pool sizes
JsonBufferPool::configure(['max_pool_size' => 50]);
// Monitor for leaks
$stats = JsonBufferPool::getStatistics();
if ($stats['current_usage'] > $stats['detailed_stats']['deallocations']) {
// Investigate buffer leaks
}Possible Causes:
- Pooling overhead for small data
- Incorrect pool configuration
- System memory pressure
Solutions:
// Check if automatic detection is working
$response->json($smallData); // Should use json_encode()
$response->json($largeData); // Should use pooling
// Verify configuration
JsonBufferPool::configure(['default_capacity' => 4096]);function streamLargeDataset($data) {
$buffer = JsonBufferPool::getBuffer(65536); // Start with 64KB
try {
$buffer->append('{"items":[');
$first = true;
foreach ($data as $item) {
if (!$first) {
$buffer->append(',');
}
$buffer->appendJson($item);
$first = false;
// Flush if buffer is getting large
if ($buffer->getSize() > 50000) {
echo $buffer->finalize();
$buffer->reset();
$buffer->append(''); // Continue stream
}
}
$buffer->append(']}');
echo $buffer->finalize();
} finally {
JsonBufferPool::returnBuffer($buffer);
}
}function processBatch($items) {
$optimalSize = JsonBufferPool::getOptimalCapacity($items);
$buffer = JsonBufferPool::getBuffer($optimalSize);
try {
$results = [];
foreach ($items as $item) {
$buffer->appendJson($item);
$json = $buffer->finalize();
$results[] = processJsonItem($json);
$buffer->reset();
}
return $results;
} finally {
JsonBufferPool::returnBuffer($buffer);
}
}class CustomJsonProcessor {
private $buffer;
public function __construct() {
$this->buffer = JsonBufferPool::getBuffer(16384);
}
public function processItem($data) {
$this->buffer->appendJson($data);
$json = $this->buffer->finalize();
$this->buffer->reset();
return $this->processJson($json);
}
public function __destruct() {
if ($this->buffer) {
JsonBufferPool::returnBuffer($this->buffer);
}
}
}function jsonPoolHealthCheck() {
$stats = JsonBufferPool::getStatistics();
$health = [
'status' => 'healthy',
'issues' => []
];
// Check reuse rate
if ($stats['reuse_rate'] < 50 && $stats['total_operations'] > 1000) {
$health['status'] = 'warning';
$health['issues'][] = "Low reuse rate: {$stats['reuse_rate']}%";
}
// Check memory usage
if ($stats['current_usage'] > 1000) {
$health['status'] = 'warning';
$health['issues'][] = "High memory usage: {$stats['current_usage']} buffers";
}
// Check pool growth
$growth = $stats['peak_usage'] - $stats['current_usage'];
if ($growth > 500) {
$health['status'] = 'warning';
$health['issues'][] = "Pool growth detected: {$growth} buffers";
}
return $health;
}// Collect metrics for APM/monitoring systems
function collectJsonPoolMetrics() {
$stats = JsonBufferPool::getStatistics();
return [
'json_pool_reuse_rate' => $stats['reuse_rate'],
'json_pool_operations_total' => $stats['total_operations'],
'json_pool_buffers_current' => $stats['current_usage'],
'json_pool_buffers_peak' => $stats['peak_usage'],
'json_pool_allocations' => $stats['detailed_stats']['allocations'],
'json_pool_deallocations' => $stats['detailed_stats']['deallocations'],
'json_pool_reuses' => $stats['detailed_stats']['reuses']
];
}// Set up alerts for pool issues
function checkJsonPoolAlerts() {
$stats = JsonBufferPool::getStatistics();
// Memory leak detection
if ($stats['current_usage'] > 2000) {
alert('CRITICAL: JSON pool memory leak detected');
}
// Performance degradation
if ($stats['reuse_rate'] < 30 && $stats['total_operations'] > 10000) {
alert('WARNING: JSON pool efficiency degraded');
}
// Capacity planning
if ($stats['peak_usage'] > 800) {
alert('INFO: Consider increasing JSON pool capacity');
}
}Symptoms: JSON operations slower after upgrading to v1.1.1
Diagnosis:
// Check if pooling is being used appropriately
$stats = JsonBufferPool::getStatistics();
if ($stats['total_operations'] === 0) {
echo "Pooling not being used - check data sizes\n";
}
// Check threshold values using public constants
if (count($arrayData) < JsonBufferPool::POOLING_ARRAY_THRESHOLD) {
echo "Array too small for pooling: " . count($arrayData) . " < " . JsonBufferPool::POOLING_ARRAY_THRESHOLD . "\n";
}Solution:
- Verify data meets pooling criteria (arrays 10+ elements)
- Check manual usage is correct
- Consider forcing pooling for specific cases
Symptoms: Application memory usage grows over time
Diagnosis:
$stats = JsonBufferPool::getStatistics();
$leaked = $stats['detailed_stats']['allocations'] - $stats['detailed_stats']['deallocations'];
if ($leaked > 100) {
echo "Potential buffer leak: {$leaked} buffers not returned\n";
}Solution:
- Review manual buffer usage for proper
returnBuffer()calls - Use try/finally blocks to ensure buffers are returned
- Reduce max_pool_size if needed
Symptoms: Variable JSON processing times
Diagnosis:
// Monitor pool sizes over time
$stats = JsonBufferPool::getStatistics();
foreach ($stats['pool_sizes'] as $pool => $size) {
echo "{$pool}: {$size} buffers\n";
}Solution:
- Adjust size categories to match actual data patterns
- Pre-warm pools during application startup
- Consider workload-specific configurations
- Let the system work automatically - The default configuration works well for most applications
- Monitor reuse rates - Target 80%+ for high-traffic applications
- Size pools appropriately - Match pool configuration to actual workload
- Use manual pooling sparingly - Only when automatic detection isn't sufficient
- Implement health checks - Monitor pool metrics in production
- Test configuration changes - Benchmark before deploying pool changes
- Handle errors gracefully - Always use try/finally for manual buffer management
- Leverage public constants - Use exposed constants for consistent configuration
- Trust error handling - The system provides precise validation messages
- Separated validation checks: Type vs range errors provide more precise messages
- Always-string return:
encodeWithPool()now always returns a string, simplifying error handling - Better fallback: Automatic fallback with internal error handling
- Testing support: All size and threshold constants are now public
- Configuration consistency: Use constants instead of hardcoded values
- Better debugging: Access to internal thresholds for diagnostics
- No duplication: Pooling decision thresholds are centralized
- Consistent behavior: Response.php and JsonBufferPool use same constants
- Easy maintenance: Single source of truth for threshold values
The JSON optimization system in PivotPHP Core v1.1.1+ provides significant performance improvements with minimal configuration required. Focus on monitoring and gradual optimization rather than complex initial setup.