Repository navigation
Proposal: call partial methods within method bindings #1085
Description
Activity
- addedenhancementProposed change to current functionalityProposed change to current functionality
on Feb 16, 2023 - addedproposalIssue raised for discussion, we do not even know if the change would be desirable yetIssue raised for discussion, we do not even know if the change would be desirable yetand removedenhancementProposed change to current functionalityProposed change to current functionality
on Feb 17, 2023 Putting aside whether or not calling
GC.AddMemoryPresure()forBitmapis a good idea (:man_shrugging:), it feels like there may not be a big enough need to warrant ageneratorchange for this.Could the
Bitmapcase be covered with some handwritten binding code instead?Are there a non-trivial amount of other classes that would want to call
GC.AddMemoryPresure()?What would we like to do? We'd like to "alter" certain methods so that we can "reasonably" tell the GC "this instance has x bytes of associated memory".
Note that
GC.AddMemoryPresure()does not take an object, so it does not tie memory to an object instance. It simply updates a global "extra memory somewhere" number.Could the
Bitmapcase be covered with some handwritten binding code instead?Depends on how things play out. If we wanted to use the
Bitmap(IntPtr, JniHandleOwnership)constructor, as demo'd above, then no, as there is no way to prevent that constructor from being emitted.If we instead use things like
Bitmap.CreateBitmap(), then yes, we could use metadata to rename that method and "replace" the public method. This in turn suggests "just replace every method that returnsBitmap", which sounds plausible until we realize that there are 85 such methods:% grep 'return="android.graphics.Bitmap"' bin/BuildDebug/api/api-33.xml.in | wc -l 85Eep?
I suspect that a
partialmethod for the "wrapper" constructor may be "enough", and should be fairly straightforward to implement (Famous Last Words™), and that it isn't necessary to providepartialmethods for every bound member.I think this is a very niche need, so if we implement it I think it should require opting in via metadata so we don't generate the
partialfor every class.Something like:
<attr path="package[@name='android.graphics']/class[@name='Bitmap']" name="constructorPartial">true</attr>
- added 2 commits that reference this issue
on Mar 14, 2023 - addedgeneratorIssues binding a Java library (generator, class-parse, etc.)Issues binding a Java library (generator, class-parse, etc.)
on Apr 11, 2023 Implemented in #1087.
- locked and limited conversation to collaborators
on Apr 12, 2024
Context: dotnet/runtime#82121
Background: When should the GC run? If a "large" object is allocated, should that change the GC heuristics for when it runs?
If someone allocates a large
Bitmap, should we GC more often on devices with low memory?We've had questions around this for quite some time, but the only "reasonable" way to alter GC heuristics was by using
GC.AddMemoryPressure()andGC.RemoveMemoryPressure(), but Mono didn't support these methods, so it was all moot: there was no way to inform the GC about "implicit" non-managed memory allocations, so we didn't.That is now changing with dotnet/runtime#82121
Meaning there is now a way to tell our GC about implicit non-managed memory usage!
Background: Binding: Consider the current (abbreviated) binding for
Android.Grpahics.Bitmap:What would we like to do? We'd like to "alter" certain methods so that we can "reasonably" tell the GC "this instance has x bytes of associated memory".
How do we do that?
Proposal: Update
generatorto emit C#partialmethods for each bound member and constructor, allowingpartialclasses to be written which allow "extra work" to be done when the bound method is executed.Open question: How many
partialmethods should we have, and where should they be called from?_Onprefix + member name + some kind of suffix. What about overloads? Should we care about overloads, or have all overloads invoke the same set ofpartialmethods?How many such
partialmethods do we need, anyway? While trying to write up the following example, it occurs to me that, while havingBitmap.CreateBitmap()callGC.AddMemoryPresure()"makes sense", it doesn't really make sense becaus it callsObject.GetObject<Bitmap>(), which means theBitmap(IntPtr, JniHandleOwnership)constructor will be invoked. This suggests we may only need one suchpartialmethod here, for constructors, and all other members aren't needed for this use case.Example:
Bitmapwithpartialmethods!Once such
partialmethods exist, we can "reasonably" updateMono.Android.dllto implement required partial methods to Do Something Useful:Meta-question: is overriding
Dispose()"sufficient enough" in practice for callingGC.RemoveMemoryPressure()? Or could this result in constantly increasing memory pressure?