Does GH's native preview pipeline have cache invalidation?

I’m maintaining a small plugin that uses a DisplayConduit to draw preview geometry for selected hidden components. It works by hooking PostDrawObjects and DrawForeground and calling pObj.DrawViewportMeshes(args) / pObj.DrawViewportWires(args) directly on each selected IGH_PreviewObject.

In large files, rhino ram grows steadily over time. And it seems it does so a lot faster while the plugin is active.

My question is about the native GH preview pipeline: does it have any cache clearing, or lifecycle management around preview mesh data that only runs when draw calls go through GH’s own pipeline? And if so, does calling DrawViewportMeshes directly from a conduit - outside that pipeline, bypass that cleanup, potentially keeping preview meshes resident indefinitely?

Hi,

if the RAM rises over time it likely has nothing to do with the rendering pipeline, because this would raise the VRAM of your video card or simply cause less and less fps on rendering over time.

Although C# or Python are memory managed, it doesn’t mean you will not create memory leaks. Noticeable memory leaks usually occur if the Garbage Collection cannot collect “unused” memory or if it cannot collect it fast enough.

A classical example to generate a memory leak is a static collection, which is not being cleared. The collection just grows over time… Static is a problem because if it exits the scope of a function/method, it will not give the reference free to be collected. It exists the entire runtime (Its the point of being static).
So I would first look and observe any static data in your code.

Another common problem is when references kept being alive in some part of the code. As soon as a object reference is somewhere in use, the garbage collector won’t collect it. If you are unsure, you can always use WeakReference wrapper, which allows the Garbage Collector to collect any reference, even if in use. But usually this won’t be required because you should always know who is consuming what at which time. If a class implements the IDisposable interface it means you are in charge to free it or you execute within a dedicated scope (“using”-> C# “with” - Python. This is usally true for data streams, where the collector doesn’t know when it can be collected.

In any case, you likely introduced the problem somewhere in your codebase. You might post some code or you could also use AI to figure out where such a memory leak could occur.

1 Like

Hi Tom! Thank you for your response. I tried to check for leaks with AI and found nothing with multiple different models. I should have mentioned that I am on mac, so it is unified memory = vram and ram are the same thing.
I’m trying to understand whether calling DrawViewportMeshes directly from a DisplayConduit outside GH’s own preview pipeline bypasses any cache expiry or cleanup that GH would normally run

Here’s the code if you can take a look

Mhh, hard to tell. It could indeed be something internal, maybe caused by the way you render it. I also remember that in the forum there were several complains about Memory Leaks with MacOS versions of GH

One thing which I noticed is the generation of PreviewArgs by using Reflection every-time the document gets re-rendered. I don’t believe this is causing the memory issue, but this is what looks most suspicious in the code. If this happens a lot of time you might generate issues. E.g. There is no need to regenerate a Material unless the color has changed. Reflection is also rather slow, but you probably do it to bypass a private modifier. But again, nothing to generate a memory leak. Another thing I like to do, is to generate debug logs. These help you to get an impression on how often something is performed. If there are duplicates for whatever reasons, if its on another thread (logging thread ids) etc.. You can quickly see it.

Another guess would be that that the singleton pattern is not thread-safe (line 22). In theory you can have multiple singleton instances when using this on different threads. Although I’m not 100% sure if this behaves like this in C#. But I remember this can be a problem in a concurrent application. But logging would help here.

1 Like

Thank you, I very much appreciate your input. I will try to work in those directions