Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] Memory leak when re-evaluating modified pattern with nested templates #2075

Open
1 task done
skyfloogle opened this issue Jan 18, 2025 · 2 comments
Open
1 task done
Labels
bug Something isn't working

Comments

@skyfloogle
Copy link

skyfloogle commented Jan 18, 2025

Operating System

Linux

What's the issue you encountered?

While putting together a pattern, I noticed that every time I modified the pattern and re-evaluated it, ImHex's memory usage went up by about 4 gigabytes. Over time, this leads to my system running low on RAM.
I have narrowed it down to the CMDL struct (quick access with CMDL cmdl @ 0xEC;) and its DictInfo<RelPtr<T>> and ListPtr<RelPtr<T>> fields. The RelPtr<T> is an optional relative pointer to a T, and the ListPtr is a relative pointer to an sized array of T. DictInfo<T> contains multiple layers of RelPtr<T>. Replacing T with char either prevents the memory increase or reduces it so much I can't measure it. I added [[inline]] attributes in many places for legibility, but removing these does not resolve the issue. I haven't been able to narrow it down further, and I'm not completely confident that this is the root cause.
I've attempted to investigate the issue myself using -fsanitize and Valgrind, but neither has given me much insight (a heap dump from Valgrind's "massif" tool identified under 200MB of data, while htop indicated memory usage was over 2GB at the time). I haven't used these tools before though, so I could be doing something wrong. I can at least verify that the issue is there in debug builds on the latest master commit as of this writing.
In the meantime, I've resorted to restarting ImHex whenever I notice memory usage is low. My 16GB system with other stuff open can only handle 2 rounds of evaluation with the full pattern, but if I replace the CMDL pointer with a char pointer it's usable.

How can the issue be reproduced?

  1. Load the provided binary and pattern
  2. Evaluate the pattern (▶️ button)
  3. Make a change in the pattern editor (e.g. remove a later field in the DATA struct, or even remove the entire thing)
  4. Re-evaluate the pattern
  5. Observe in htop or similar that memory usage goes up by several gigabytes (or, in the case of removing the entire pattern, doesn't go down at all)

ImHex Version

1.36.2 and 2ba7db1

ImHex Build Type

  • Nightly or built from sources

Installation type

Tried imhex-bin off AUR, the nightly AppImage, and a local build

Additional context?

I'm running EndeavourOS with KDE/Wayland on an AMD Ryzen 5 4500U with integrated graphics.

cgfx.zip contains model.cgfx (the binary, an intermediate build artifact of one of my projects) and cgfx.hexpat (the pattern).

@skyfloogle skyfloogle added the bug Something isn't working label Jan 18, 2025
@WerWolv
Copy link
Owner

WerWolv commented Jan 18, 2025

Hey, thanks for the report! I'll definitely look into what's causing this. There's various issues currently when nesting template types but I wasn't aware of such a massive memory leak

@skyfloogle
Copy link
Author

skyfloogle commented Jan 26, 2025

I'm not sure whether this is related, but after further work on my pattern, memory appears to be ballooning during parsing, and doesn't depend on the pattern data being present at all. My current pattern uses 11.3GB of RAM in plcli when applied to an empty file.

After investigating further, it seems to be at least partly because when template parameters are involved, the entire ASTNodeTypeDecl is cloned, including the type parameters.

I'm not very familiar with the code's structure and how easy it is to change things, but would it be possible to have template implementations be represented by some object with weak references to the definitions of its type parameters and to the relevant template definition?
It's also possible that the data being cloned really shouldn't be this big, and maybe some stuff could be shrunk or shared there (e.g. maybe strings could be shared with some kind of string pool, or stored as slices of the original source code).

Here's my current pattern. It seems to be particularly caused by a rather deep nesting of templates: the name in the LutInfo struct is potentially quite deep, possibly 20+ levels of structs inside structs, many of which are templates. It can also be worked around by removing the DictInfo<CMDL> from the DATA at the bottom, as that is presumably where the biggest clone happens.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants