Eu finalmente encontrei o problema. Há uma seção de configuração web.config opcional para o cache do ASP.NET: link
A configuração padrão é absolutamente absurda para caixas de 32 bits com mais de 2 GB de RAM: ela começa a descartar itens do cache, se menos de 10% de RAM física estiver disponível . Tendo e. g. 4 GB de RAM instalados e um limite de 2 GB por processo, isso nunca acontecerá. Portanto, o tamanho do cache (e, portanto, o tamanho do heap, principalmente o heap da geração 2) está aumentando e aumentando até que você execute o OutOfMemoryExceptions ou atinja o limite do pool de aplicativos.
Agora adicionei isso ao meu web.config:
<configuration>
<system.web>
<caching>
<cache privateBytesLimit="400000000" privateBytesPollTime="00:01:00" />
</caching>
</system.web>
</configuration>
Além disso, defini os seguintes limites para o pool de aplicativos:
- 1400 MB de limite de memória virtual
- 800 MB de limite de memória usado (bytes privados)
Veja este ótimo artigo para informações sobre esses valores: link
Agora, se eu carregar o teste do meu aplicativo de forma que muitos objetos serão adicionados ao cache em pouco tempo, poderei ver o contador de desempenho de trims do cache ASP.NET aumentando, e o uso da memória permanece constantemente sob o meu limites de reinicialização.