-
-
Notifications
You must be signed in to change notification settings - Fork 126
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
Memory management for WinRT Classes #443
Comments
So I don't fully understand the design yet, which is why I was slow to replying -- but I think this will mostly mitigate the challenges here. We'd have to implement an interface to tell Dart how to dispose of COM / WinRT objects, but the free call will be made automatically when the object goes out of scope (and there will be a consistent way to call this manually). While the core Finalizer mechanism is now available in Dart 2.17, we need the final checkbox from the issue above to be completed in order that we can use it from Dart code. Here's the design doc: |
Thanks, that's great! This will make using WinRT APIs much easier for consumers. |
Does it make sense for this work to be completed first ({cough} @dcharkes 🤣) , and then take another look at our memory management strategy? |
Yes! 😄 I'm making progress on a prototype that will enable us to use NativeFinalizer with Unfortunately, I cannot give any guarantees when this will be fully supported. (Or if the current implementation approach is the right one.) In other words: We're working on it. 🤞 |
Yeah, it makes sense :) |
Just a question, @dcharkes -- have you looked at While they're designed with OLE/COM in mind, they are generally applicable. I've seen one reference to suggest that there's a slight overhead with these calls, but I can imagine it might be a rounding error for the kind of usage we're talking about here. |
I have not. That might just be the perfect solution! The issue with
https://devblogs.microsoft.com/oldnewthing/20060915-04/?p=29723
@timsneath can you check that if you change And yes, then you could use |
I'll give it a try! |
I've released package:ffi 2.0.0 - happy memory managing! 😀 |
Great, thanks! |
Originally posted by @halildurmus in #431 (comment)
Assume that we're using the
Mixin
model for generating WinRT classes.There are some cases where we can't deallocate pointers in the generated code. Therefore, it is the consumers' responsibility to deallocate them once they're done using them.
These are:
Calendar
's pointer (these pointers are allocated by constructors such asCalendar
's default constructor, factory constructors, methods, properties, or by consumers usingActivateObject
or other helper methods)ICalendar
andITimeZoneOnCalendar
IVector<T extends IInspectable>
orIVectorView<T extends IInspectable>
e.g.IVector<StorageFile>
. As of now, these are exposed asPointer<COMObject>
. We only auto-generate APIs that returnIVector<String>
andIVectorView<String>
at the moment but we will add support for these in the future. Here is the one I manually generated....and probably much more in the future as the WinRT projection matures (asynchronous APIs, IMap & IMapView...).
The problem is that there are many situations where the consumers need to free pointers manually and I think it is pretty common to forget freeing some of the pointers (especially if you're using a lot of them). Another thing that is quite painful to deal with is that if you accidentally call
free
method twice on the same pointer, the process will crash and good luck figuring out the source of the problem (I got bitten by this many times :( ).I've been trying to find a way to fix these issues for the past few days and I have some ideas I'd like to share with you.
I'll start with the first design. We could consider introducing a class that manages the pointers that could not be freed in the generated code:
This class would contain a
static
allocator to be used by the generated code and a static method to free all pointers. We would expose this to the outside world so that the consumers would have a way of freeing all pointers by calling just a single method once they're done using WinRT APIs.Here are the cases where we need to modify the generator to use this allocator:
WinRTAllocator.allocator
totoInterface
method as a parameter)IVector<T extends IInspectable>
orIVectorView<T extends IInspectable>
...and much more in the future...
This design is much simpler to use, but if consumers use WinRT APIs heavily, I'm worried that the memory usage may be higher until they call
WinRTAllocator.freeAll()
(there may be some cases where the consumer is using tightly coupled APIs and because of this they can't callfreeAll
method between calls and must wait for all calls to complete).To solve this, here is the final design I came up with. First, we could create our own
Arena
implementation by slightly modifyingdart:ffi
's implementation to allow freeing specific pointers from the_managedMemoryPointers
list (by modifyingArena
'sfree
method):(I'd like to point out that calling
WinRTAllocator
'sfree
multiple times on the same pointer won't crash your process as the implementation checks if the pointer exists in the_managedMemoryPointers
list before calling the native API.)Then, we could create a
dispose
method inIInspectable
:...and modify WinRT classes and mixins like this:
With this design, consumers have the flexibility to use the
dispose
method of the WinRT classes in combination with thefreeAll
method of theWinRTAllocator
for memory management. They can decide which option is more suitable for their needs or preferences. Some might prefer to just usefreeAll
for its simplicity while others may use both of them to make their applications more efficient.The text was updated successfully, but these errors were encountered: