25000 Engines divided across 25 runtimes take up 11GB of memory.
We've reproduced these numbers using a trivial native test program (no .NET, no ClearScript), so V8's implementation appears to be the cause.
Since V8 runtimes don't support concurrent access, why keep a large number of engines (per runtime) in memory? If you're using them just to hold data, it might make sense to use regular data structures instead, moving data into a script engine only when necessary
for script execution.
Is there a way I can have multiple js contexts within a single engine (something like V8 isolates?)?
ClearScript's V8 runtimes are
based on V8 isolates, and they're quite expensive. A reasonable guideline for server applications is that you create one per pool thread, or roughly one per CPU core.
In any case, if you're in control of the scripts you run and can ensure that they're well-behaved, you should be able to simulate multiple contexts by adopting simple rules about how data within the engine is organized and shared.
Or what are other ways to reduce the memory usage?
Holding fewer engines in memory is your best bet.