toddams/RazorLight

Removing RazorEngine temporary files and memory leak.

Closed this issue · 7 comments

Hello everyone.

I'm using the library to generate HTML' strings, but I've been experiencing some problems.
Every time I build a template it generates a temporary files which has to be deleted manually and seems the RAM memory does not release memory after it, so it becomes bigger and bigger after every template.

Does someone know how to solve this problem? (delete temp files and memory problem)
I'm using NET6 and RazorLight version 2.3.0.

Code to generate HTML given a template and model:

  var engine = new RazorLightEngineBuilder()
            .UseMemoryCachingProvider()
            .Build();

string result = await engine.CompileRenderStringAsync($"Template", template.HTML, jsonObject);

image

Thank you in advance.

I'll keep saying what I tell people - Use a real profiling tool like Redgate ANTS memory profiler. Nobody has been able to point to where RazorLight is a problem when they say they have memory utilization issues. One guy finally fessed up that he was trying to print to PDF using RazorLight a 1GB+ string on .NET Framework no less.

Hello @jzabroski and thank you for your answer.
I'm using Prometheus and checking where the memory is being used (endpoints that use Razor tool).

Problem is that Razorlight is generating CSS depending on the models, but is dont releasing memory, so when its full, the system resets and starts the flow again. Here you can see the image:

image

I don't really know if there's a solution.

What do you mean, RazorLight is generating CSS? Can you share some sample code?

Even with Prometheus, you can and should host it locally, but I do understand that perhaps someone with more experience (who may not be on your team any more) maybe set up Prometheus, or maybe your team doesn't practice using local environments for some reason. In any case, you can definitely set up Prometheus locally via docked - you can then piggy back on another dockerfile example to run profiling inside that new image container https://www.mytechramblings.com/posts/profiling-a-net-app-with-dotnet-cli-diagnostic-tools/ It would be a huge dockerfile and image but doable.

I am trying to solve your problem by avoiding it, since I don't agree with the approach.

Who is consuming the html end product? Are you using partial views for the css? I think your mistake probably starts with how you are modeling template.HTML via a templateRepository. Part of that mistake is probably induced by the demo code that demonstrates using EF to store templates. Just thinking out loud: Part of the problem is that your repository should be at a lower level of abstraction, so that recursively resolved resources in the template can be fulfilled by a File Provider API. I dont have a demo of this working, but someone else raised a similar issue in #510

Hello.

We're using the html end product to inject styles to our different websites. Maybe the problem is that is compiling huge loads of templates(with a lot of CSS lines) and can't really solve it. We're working on checking why is not disposing but will try different options.

Again thank you for your help and your answer. I'll keep an eye to the issue and prove if it can help.

If you were to File.ReadAllText each file into List, how big does it get? How many templates are there and how big is each one? I'm trying to understand how just stylesheets use up this much memory.

We're using the html end product to inject styles to our different websites. Maybe the problem is that is compiling huge loads of templates(with a lot of CSS lines) and can't really solve it

  1. Why can't you just use static compilation of your sheets, a la:
    @import 'colors';
    @import 'headlines';
    @import 'layout';
    @import 'lists';
    // etc.
    And then applying those styles globally to your site via something like:
    <link rel="stylesheet" href="all-my-styles.css" />
  2. The only reason I can make sense of your approach is if you are injecting the style element into a particular node via shadow DOM. But perhaps there is some other reason why your team is doing things this way.

Every time I build a template it generates a temporary files which has to be deleted manually and seems the RAM memory does not release memory after it, so it becomes bigger and bigger after every template.

I had the same memory leak issue. It was from creating a new engine before each render. Thus the cache could not be used and each render compiled the template again and the memory kept going up.

The resolution was to create the engine once at application start-up and re-use it (inject via DI).