Logo

Tuning S&Box server performance

Tuning S&Box server performance

Source 2 + .NET 9 + C#: what actually consumes CPU and RAM on S&Box, how to monitor, and how to tune allocation at VeryCloud (and the gamemode code).

Introduction

S&Box is technically much heavier than GMod: Source 2 engine, .NET 9 runtime, advanced physics, JIT-compiled C# scripts. Understanding what consumes is the key to picking the right plan and tuning your gamemode. This guide gives you the server-side levers and best practices on the dev side.

Prerequisites

  • An active S&Box server at VeryCloud
  • Access to resource graphs in the Wisp panel
  • If you're developing your gamemode: basic C# knowledge

Step 1: Understand S&Box load

Main resource consumers:

ResourceLoad source
CPUSource 2 physics, gamemode tick, .NET JIT, AI, scripts
RAMLoaded assets, complex scenes, NetList/NetDictionary, C# allocations
NetworkEntity sync, physics props, custom Rpc
DiskLow at runtime (cloud packages cached), spike at boot

Source 2 uses multithreading better than Source 1, but most gameplay still runs on a single main thread where CPU frequency matters more than core count.

Step 2: Monitoring from Wisp

In the Console tab, you have real-time graphs:

  • CPU usage: if you saturate a core (often visible as %), it's the gamemode tick struggling
  • Memory usage: if you approach the RAM limit of your plan, it's leak or assets too heavy
  • Disk I/O: should stay low at runtime; continuous spike often signals bad logging

Step 3: Pick the right VeryCloud plan

VeryCloud S&Box plans are tuned for different profiles:

PlanCPURAMBest for
SboxDev2 vCPU2 GBTest, dev, friend party
SboxPlus4 vCPU8 GBPublic sandbox 16-24 players
SboxPro10 vCPU32 GBHeavy RP / Battle Royale 32+

Simple rule: if your CPU caps >80% during peaks, scale up. If RAM is fine but tick is bad, you lack CPU frequency.

Step 4: Gamemode-side optimizations (C#)

If you write your own gamemode, golden rules:

Avoid allocations in the tick loop

// BAD: allocates a list every tick
protected override void OnFixedUpdate()
{
    var players = new List<Player>();
    foreach (var c in Scene.GetAllComponents<Player>())
        players.Add(c);
}

// GOOD: reuse the list
private List<Player> _players = new();
protected override void OnFixedUpdate()
{
    _players.Clear();
    foreach (var c in Scene.GetAllComponents<Player>())
        _players.Add(c);
}

Use [Sync] sparingly

Each [Sync] property generates network traffic. Only sync what truly needs to be visible client-side.

[Rpc.Broadcast] vs [Rpc.Owner]

Prefer [Rpc.Owner] or [Rpc.Host] when only one recipient is concerned. Broadcast sends to everyone — expensive at scale.

Step 5: Reduce server-side assets

The server loads all models and materials referenced by the scene, even if it doesn't render them. Some leads:

  • Limit unique props in a map
  • Avoid useless LODs server-side (collision is what really matters)
  • Prefer shared materials between similar props

Step 6: Schedules for planned restarts

To avoid slow memory accumulation (typical in .NET with uncollected LOH GC), schedule restarts:

  1. In Wisp, open Schedules
  2. Create a Daily or Weekly schedule
  3. Action: Power → Restart
  4. Time: off-peak (3 AM for example)

Announce the restart 5 min before via the gamemode (say or broadcast) to avoid cutting an active session.

Step 7: Troubleshoot specific CPU spikes

If you see a sustained 100% CPU spike:

  1. Console → status: check there isn't an absurd number of entities
  2. Ask a player what was happening just before the spike (often a looped gamemode script)
  3. If you have gamemode source, look at OnFixedUpdate and long loops
  4. Restart to stop the immediate effect, then investigate cold

Troubleshooting

RAM slowly grows and never goes down

  • C# memory leak (often event subscribers never unsubscribed)
  • Scheduled restarts as a workaround while you fix the code
  • Profile with dotMemory or perfview if you can grab a dump

Server TPS / framerate drops with many players

  • Too many per-tick allocations (see step 4)
  • Too many broadcast RPCs
  • Useless property sync

Periodic lag spikes

  • .NET GC collecting — allocate less
  • Disk I/O (logs too verbose)

Useful commands

# View CPU/RAM in Wisp console
# -> top graph in Console view

# Force a manual GC (from gamemode C# code)
GC.Collect();
GC.WaitForPendingFinalizers();

Conclusion

Optimizing S&Box is 80% gamemode (C# code) and 20% server allocation. VeryCloud hardware is sized for serious Source 2, but no machine compensates for a gamemode allocating 50 lists per tick. Profile, measure, restart regularly.

Going further: profiling with dotMemory, JetBrains Rider profiler, observability via custom Prometheus exporter in your gamemode.

Resources

Join our Discord community server

For any questions, suggestions, or just to chat with the community, join us on Discord!

900+Members