Skip to content

Memory leak when linking to MathJax directly #3591

Description

@jajaperson

Issue Summary

I am using a fork of rehype-mathjax which upgrades from v3 to v4, in a project containing approximately 1,900 markdown files, the majority of which contains maths. Recently the build has been surpassing 4 GB of memory usage on my personal machine, and MathJax seems to be the culprit, as disabling it removes the memory leak.

Steps to Reproduce:

Run pnpm build on the project linked above.

I know this can hardly be considered a “minimal” reproduction, but this bug obviously requires a substantial number of files to reproduce. If there is something else you would like me to try, please let me know.

For what its worth, the rehype-mathjax fork follows the approach of linking to MathJax directly. Unfortunately my PR to remark-math has been open for 5 months with no response.

Technical details:

  • MathJax/src Version: 4.1.3
  • OS: 26.5.1
  • Node: 24.7.0

Activity

  1. dpvc commented on Jul 16, 2026

    @dpvc
    Member

    Thanks for your report. I am able to verify the problem you are seeing, though I haven't fully diagnosed it yet. The majority of the problem seems to be due to the large number of instances of the CHTML output jax that are involved here, so I suspect that it is the font data that is causing the problem. I will have to track it down, but wanted to give you some options in the meantime.

    The /@jajaperson+rehype-mathjax package is creating the input and output jax and the MathDocument for each of the 1,900 documents that you process. You also create the DOM adaptor and register/unregister the HTML handler for each document. Not all of that is necessary to do each time, and that is contributing to the memory problem. It also degrades the performance, particularly recreating the output jax, which has to process the font data each time as it creates its own FontData instance.

    Fortunately, the output jax can be reused, which eliminates both the performance hit, as well as reducing the memory usage. You also only need to create the DOM adaptor and register the HTML handler once up front.

    Here are some changes that I think will reduce the problem that you are having:

    In the create-renderer.js file, add

    const adapter = liteAdapter();
    const handler = registerHtmlHandler(adapter);

    right after all the import commands, and then remove

      /** @type {HtmlHandler<LiteElement | LiteText, LiteText, LiteDocument>} */
    let handler

    from the createRenderer() function. Also, remove

          const adapter = liteAdapter()
          handler = registerHtmlHandler(adapter)

    from the register() function within it. Finally, replace

          mathjax.handlers.unregister(handler)

    in the unregistered() function with

          const jax = document.outputJax;
          jax.reset();
          if (jax.chtmlStyles) jax.chtmlStyles = null;
          if (jax.svgStyles) jax.svgStyles = null;

    Then in chtml.js, add

    let chtml;

    at the top, and replace

      return createRenderer(options, new Chtml(options.chtml))

    with

      chtml ??= new Chtml(options.chtml);
      return createRenderer(options, chtml);

    Do the similar thing in svg.js.

    These changes will allow you to reuse the output jax, rather than re-instantiating over and over again. If you are not defining new macros, it would be possible to do something similar with the input jax. Even the mathjax.document() value could be reused in that case. It looks like you are only used \def to create \fCenter as \vdash, and one other macro. Those could be added to your main macro list, or, since you aren't redefining any standard macros, you could just reuse the input jax as it is, as those two macros won't interfere with anything if they are held over from one to the next. That gives me pretty stable memory usage; I think you should find the same.

  2. added a commit that references this issue on Jul 17, 2026
  3. jajaperson commented on Jul 17, 2026

    @jajaperson
    Author

    Thanks, I have followed your suggestion and this has completely fixed the issue for me, memory usage is down to about 181 kB and build time has halved. I am happy if you close this, but maybe you still want to investigate why re-initializing MathJax caused a problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions