Skip to content

Opening IMetaDataEmit causes 40-50% additional memory usage #13093

Closed
@discostu105

Description

@discostu105

I am (finally) raising this issue to point out a known problem, that we've had for a long time and that is repeatedly causing us problems with customers with our Profiler (Dynatrace .NET Code Module).

Opening IMetaDataEmit causes significant memory overhead. Concretely, it allocates ~50% of the size of a Module in additional memory. AFAIK this comes from the fact that the metadata tables are being copied into new datastructures, which are then writable to be able to emit new metadata.

In fact the same issue has been raised by us already in 2008 (!) on Microsoft connect. Although connect is long offline, I still have the original answer from back then:

Posted by Microsoft on 8/26/2008 at 10:23 AM

Hello, Andreas, thank you for entering this into Connect. As we've discussed, this will be an item for us to consider in future releases, though we will most likely not have time to address this in our next major release. I will therefore be closing this issue for now, but the ID you have (361070) is still valid for tracking this. As you continue to receive feedback from your own customers on this, we'd like to hear specific complaints they have.

For completeness, I'm pasting below some of my comments from the email thread we've had on this issue.

Our understanding of the situation is that opening one IMetaDataEmit per module will cause, at worst, a new allocation the size of the existing metadata in that module, in order to make it writeable. Generally, that will translate to about the 40-50% memory usage Karel mentioned below, assuming on average a given module's metadata accounts for about 40-50% of its size. It's important to note those percents are based on the size of the modules, and not the size of the overall memory usage of the app at run-time. So it will depend on the extent of a given application's memory usage, and the contents of its modules' metadata, as to whether this would actually be a significant overhead for that app. I suspect some apps will be affected more by this issue than others.

Further, just increasing memory usage doesn't necessarily translate into a poor experience. For example, if the original metadata just gets paged out of memory and is replaced by the IMetaDataEmit (writeable) copy, then even though committed memory increases, the working set might actually remain constant. I don't know if that's the case with your scenarios, but it's worth measuring.

Our profiler instruments a couple of large assemblies always (mscorlib/System.Private.CoreLib, System, System.Data, ...), others on demand or per customer configuration. Theoretically a customer can configure to instrument methods in almost all assemblies. Thinking of a large application with hundreds of assemblies, with multiple hundreds of Megabytes in size, we're dealing with a huge overhead.

There are customers that run hundreds of .NET Apps (e.g. AppPools) on a single machine. It's often hard to explain the additional (total) memory consumption, just by installing our Profiler. Nowadays, where you typically pay-as-you-go for resources (cloud!), this becomes a real cost factor.

So, my request is: Can we find a way to improve this situation? In my naive mind, it should be possible to avoid copying the whole MD table and allocate only memory for newly emitted metadata entries. Lookup functions should be able to differentiate and look into the right datastructures. I know some MD tables are based on offsets (e.g. Fields and Params), but a mapping function should be able to handle that when resolving metadata. I am hoping for a discussion, so we can find a potential solution to fix this.

Metadata

Metadata

Assignees

Labels

area-Diagnostics-coreclrenhancementProduct code improvement that does NOT require public API changes/additionstrackingThis issue is tracking the completion of other related issues.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions