-
Notifications
You must be signed in to change notification settings - Fork 0
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
Make memory handling safe and comprehensible #8
Comments
I agree that we have to settle on one strategy here, but I am not 100% clear on which way to go. What speaks against having a high level interface, for example: I must admit, I don't have a lot of experience with memory management in C and I do find the garbage collector in Julia to be very convenient in general. |
Same here :) However, those functions will make it hard to understand for users when to call a destructor, since the dynamic allocation is hidden within the function (actually, some of our current tests are also not clean in this respect). Therefore, I would prefer to use the following strategy: Instead of high-level functions such as |
This could be quite nice from a usability standpoint. Take for example this code:
And then we could have (The way I have done it above, could also allow to revert one of the custom changes in generator.jl where the automatically generated struct for UA_NodeId is manually replaced... It felt like this is something that would be easily breaking in the future anyhow.) What happens if I construct a server, add a variable to it, delete the nodeid with From a user perspective, it would of course be nice if that doesn't result in a crash. |
Made a test here. The server is startable. If I kill it (through multiple CTRL+C) and then try to start it again, it seems faulty. Don't understand that part yet. https://github.com/thomvet/open62541.jl/blob/thomvet-typescleanup/src/memorytest.jl |
That is really a good point. I would not know without checking the source code and we better don't expect the user to know :) As far as I know, the fact that the server is startable is not even a clear indicator that the server makes its own copy of the UA_NodeID. It could instead only crash in certain situations when the memory is allocated for other purposes. But this is where my C knowledge really is limited. The only safe way to know is probably to follow the call stack, e.g., here and here. When it comes to those questions, I hope there is a clear structure that open62541 is following. Maybe it is helpful to take a closer look at the corresponding source code and documentation. Unfortunately, I am currently relatively busy but will hopefully come back to this next week. |
The manual (https://www.open62541.org/doc/1.3/server.html?highlight=stack%20evaluates) says it makes a copy:
(emphasis added is mine) and the C-source code of UA_addVariableNode also agrees! So, that should be fine. Also, this kind of memory management (the "free"-ing part) only truly matters if repeated calls occur? So, it's critical for things like data reading and updating functions, but maybe less so for creating nodes (apart from avoiding crashes and unintended behavior of course)? |
I have had a little bit of a play with wrappers for NodeIds. Basically, I wanted to see whether there is good way of keeping the memory management on C-side and at the same time having Julia's garbage collector releasing the memory when there is no more reference to the respective pointer. By getting inspired from other libraries (here: https://github.com/SciML/Sundials.jl/blob/efd1a0a04a99ed68b3bc5f42e94e8e2aecbfdf09/src/nvector_wrapper.jl and here: https://github.com/trixi-framework/P4est.jl/blob/main/src/pointerwrappers.jlfrom for example), I made some progress. The result is here: https://github.com/martinkosch/open62541.jl/blob/wrapper-test/src/wrappers.jl Maybe there is a way of making this pretty neat in the end with an "out of the box" functionality using the low-level UA... API where one has to keep freeing memory in mind and a higher level one where things are getting taken care of in an easier fashion. I'll keep exploring a little bit :) |
This progressed quite a bit with #18 and co. Even though the high level interface is not 100% complete yet, I think the pathway towards making things comprehensible is clear now. Just needs to be driven to completion, but I suggest to do that via more specific issues in the future. |
Some variables can currently be created either in Julia or C memory space, e.g.,
UA_NODEID_NUMERIC(nsIndex::Integer, identifier::Integer)::UA_NodeId
vs.UA_NodeId_new()::Ptr{UA_NodeId}
This makes using the package incomprehensible and prone to memory errors.
I can only think of solving this by allocating everything dynamically within the C memory space for now, i.e. use
UA_..._new()
for all variables and encourage using corresponding destructors. All other functions should then be removed or moved to another package with high-level functionality. Is there another way?The text was updated successfully, but these errors were encountered: