mirror of
https://github.com/SoPat712/allstarr.git
synced 2026-02-09 23:55:10 -05:00
Remove memory optimization markdown file
This commit is contained in:
@@ -1,191 +0,0 @@
|
|||||||
# Memory Optimization Recommendations for Allstarr
|
|
||||||
|
|
||||||
## Current Implementation Status
|
|
||||||
|
|
||||||
✅ **COMPLETED**: Mark-for-deletion system with 24-hour delay
|
|
||||||
✅ **COMPLETED**: Persistent favorites tracking using JSON files
|
|
||||||
✅ **COMPLETED**: Cache-first copying for favorites (avoids re-downloads)
|
|
||||||
✅ **COMPLETED**: Dependency injection for CacheCleanupService to process pending deletions
|
|
||||||
|
|
||||||
## Memory Optimization Strategies
|
|
||||||
|
|
||||||
### 1. Collection Optimizations
|
|
||||||
|
|
||||||
**Current Issues:**
|
|
||||||
- Multiple `List<Song>`, `List<Album>`, `List<Artist>` collections created during searches
|
|
||||||
- Large `Dictionary<string, object?>` objects for Jellyfin metadata
|
|
||||||
- Concurrent collections like `ConcurrentDictionary<string, SessionInfo>` for sessions
|
|
||||||
|
|
||||||
**Recommendations:**
|
|
||||||
```csharp
|
|
||||||
// Use ArrayPool for temporary collections
|
|
||||||
private static readonly ArrayPool<Song> SongArrayPool = ArrayPool<Song>.Shared;
|
|
||||||
|
|
||||||
// Use Span<T> for temporary operations
|
|
||||||
ReadOnlySpan<Song> ProcessSongs(ReadOnlySpan<Song> songs) { ... }
|
|
||||||
|
|
||||||
// Use IAsyncEnumerable for streaming large results
|
|
||||||
IAsyncEnumerable<Song> SearchSongsStreamAsync(string query);
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. JSON Serialization Optimizations
|
|
||||||
|
|
||||||
**Current Issues:**
|
|
||||||
- Heavy use of `JsonSerializer.Deserialize<Dictionary<string, object?>>()`
|
|
||||||
- Multiple serialization/deserialization cycles for caching
|
|
||||||
|
|
||||||
**Recommendations:**
|
|
||||||
```csharp
|
|
||||||
// Use System.Text.Json source generators for better performance
|
|
||||||
[JsonSerializable(typeof(List<Song>))]
|
|
||||||
[JsonSerializable(typeof(Dictionary<string, FavoriteTrackInfo>))]
|
|
||||||
public partial class AllstarrJsonContext : JsonSerializerContext { }
|
|
||||||
|
|
||||||
// Use JsonDocument for read-only scenarios instead of Dictionary
|
|
||||||
JsonDocument.Parse(json).RootElement.GetProperty("Items")
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Caching Strategy Improvements
|
|
||||||
|
|
||||||
**Current Issues:**
|
|
||||||
- File-based caching creates multiple copies of data
|
|
||||||
- Redis and file caches can contain duplicate data
|
|
||||||
|
|
||||||
**Recommendations:**
|
|
||||||
```csharp
|
|
||||||
// Implement cache eviction policies
|
|
||||||
public class LRUCache<TKey, TValue> where TKey : notnull
|
|
||||||
{
|
|
||||||
private readonly int _maxSize;
|
|
||||||
private readonly Dictionary<TKey, LinkedListNode<CacheItem>> _cache;
|
|
||||||
private readonly LinkedList<CacheItem> _lruList;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use weak references for large objects
|
|
||||||
private readonly WeakReference<List<Song>> _cachedSongs = new(null);
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. String Interning and Optimization
|
|
||||||
|
|
||||||
**Current Issues:**
|
|
||||||
- Many duplicate strings (artist names, album titles) across collections
|
|
||||||
- Path strings created repeatedly
|
|
||||||
|
|
||||||
**Recommendations:**
|
|
||||||
```csharp
|
|
||||||
// Use string interning for common values
|
|
||||||
private static readonly ConcurrentDictionary<string, string> InternedStrings = new();
|
|
||||||
public static string Intern(string value) => InternedStrings.GetOrAdd(value, v => v);
|
|
||||||
|
|
||||||
// Use StringBuilder for path construction
|
|
||||||
private static readonly ThreadLocal<StringBuilder> PathBuilder =
|
|
||||||
new(() => new StringBuilder(256));
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. Background Service Optimizations
|
|
||||||
|
|
||||||
**Current Issues:**
|
|
||||||
- Multiple background services running simultaneously
|
|
||||||
- Potential memory leaks in long-running services
|
|
||||||
|
|
||||||
**Recommendations:**
|
|
||||||
```csharp
|
|
||||||
// Implement proper disposal patterns
|
|
||||||
public class CacheCleanupService : BackgroundService, IDisposable
|
|
||||||
{
|
|
||||||
private readonly SemaphoreSlim _semaphore = new(1, 1);
|
|
||||||
|
|
||||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
|
||||||
{
|
|
||||||
using var _ = await _semaphore.WaitAsync(stoppingToken);
|
|
||||||
// ... cleanup logic
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Dispose()
|
|
||||||
{
|
|
||||||
_semaphore?.Dispose();
|
|
||||||
base.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 6. HTTP Client Optimizations
|
|
||||||
|
|
||||||
**Current Issues:**
|
|
||||||
- Multiple HTTP clients for different services
|
|
||||||
- Large response buffers
|
|
||||||
|
|
||||||
**Recommendations:**
|
|
||||||
```csharp
|
|
||||||
// Use HttpClientFactory with proper configuration
|
|
||||||
builder.Services.AddHttpClient<DeezerMetadataService>(client =>
|
|
||||||
{
|
|
||||||
client.DefaultRequestHeaders.Add("User-Agent", "Allstarr/1.0");
|
|
||||||
client.Timeout = TimeSpan.FromSeconds(30);
|
|
||||||
})
|
|
||||||
.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
|
|
||||||
{
|
|
||||||
MaxConnectionsPerServer = 10,
|
|
||||||
PooledConnectionLifetime = TimeSpan.FromMinutes(15)
|
|
||||||
});
|
|
||||||
|
|
||||||
// Stream large responses instead of loading into memory
|
|
||||||
using var stream = await response.Content.ReadAsStreamAsync();
|
|
||||||
using var reader = new StreamReader(stream);
|
|
||||||
```
|
|
||||||
|
|
||||||
### 7. Container Memory Limits
|
|
||||||
|
|
||||||
**Docker Configuration:**
|
|
||||||
```dockerfile
|
|
||||||
# Set memory limits in docker-compose.yml
|
|
||||||
services:
|
|
||||||
allstarr:
|
|
||||||
deploy:
|
|
||||||
resources:
|
|
||||||
limits:
|
|
||||||
memory: 512M
|
|
||||||
reservations:
|
|
||||||
memory: 256M
|
|
||||||
```
|
|
||||||
|
|
||||||
**Runtime Configuration:**
|
|
||||||
```csharp
|
|
||||||
// Configure GC for container environments
|
|
||||||
GCSettings.LatencyMode = GCLatencyMode.Batch;
|
|
||||||
GC.Collect(2, GCCollectionMode.Optimized);
|
|
||||||
```
|
|
||||||
|
|
||||||
## Immediate Actions (Priority Order)
|
|
||||||
|
|
||||||
1. **Enable GC monitoring** - Add memory usage logging to identify hotspots
|
|
||||||
2. **Implement cache size limits** - Prevent unbounded growth of in-memory caches
|
|
||||||
3. **Use object pooling** - For frequently allocated objects like Song/Album/Artist
|
|
||||||
4. **Stream large responses** - Instead of loading entire JSON responses into memory
|
|
||||||
5. **Optimize JSON serialization** - Use source generators and reduce Dictionary usage
|
|
||||||
|
|
||||||
## Monitoring Recommendations
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
// Add memory monitoring to Program.cs
|
|
||||||
builder.Services.AddHostedService<MemoryMonitoringService>();
|
|
||||||
|
|
||||||
public class MemoryMonitoringService : BackgroundService
|
|
||||||
{
|
|
||||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
|
||||||
{
|
|
||||||
while (!stoppingToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
var memoryUsage = GC.GetTotalMemory(false);
|
|
||||||
var gen0 = GC.CollectionCount(0);
|
|
||||||
var gen1 = GC.CollectionCount(1);
|
|
||||||
var gen2 = GC.CollectionCount(2);
|
|
||||||
|
|
||||||
_logger.LogInformation("Memory: {Memory:N0} bytes, GC: Gen0={Gen0}, Gen1={Gen1}, Gen2={Gen2}",
|
|
||||||
memoryUsage, gen0, gen1, gen2);
|
|
||||||
|
|
||||||
await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
Reference in New Issue
Block a user