Closed PouyaMoradian closed 8 years ago
Hi @pouyamoradian!
The short story is, use copy constructors to make things easy for application developers. The buffer is managed from Java classes and freed by garbage collection.
The long story. Read chapter 4.14 "Memory Management" of the XFS API (CWA XXX-1). It mentions the to XFS functions WFMAllocateBuffer and WFMAllocateMore. The service provider uses this functions to allocate memory for results.
One problem is, the results differ from different command and XFS versions. They can be simple but also were complex. Lets take WFSCIMSTATUS as an example. A SPI calls WFMAllocateBuffer to allocate memory for the basic WFSCIMSTATUS data structure. But WFSCIMSTATUS contains also a Pointer to a NULL-terminated array of pointers to WFSCIMINPOS structures. The SPI uses WFMAllocateMore to allocate memory for these nested data structures, the XFS Manager then links the allocated memory to the original memory for WFSCIMSTATUS. This means the WFSResult contains a single Pointer, where the XFS Manager knows which memory blocks also depend on this pointer. So calling WFSFreeResult for WFSCIMSTATUS will also result in freeing the memory for the WFSCIMINPOS data structures linked to WFSCIMSTATUS.
So as the XFS application developer you are responsible to call WFSFreeResult for any result you get and don't need anymore. When I first started with O2Xfs I did a 1:1 mapping to XFS, keeping the Java code close to the XFS API. So I did call WFSFreeResult for every result. Then I started with O2XfsOperator a application using the API. Now I had to actually work with the data received, and soon it turned out to be complicated to work with the data structures. There would be so many WFSFreeResult calls in the application, that sooner or later there will be a memory leak.
As I of now I'm still trying to find the best way between XFS and Java. A good way would be to simple map the data structures to plain Java objects as soon as possible and call WFSFreeResult immediate. Then you are save in the Java world. But there are many things you need to know to map the data structures behind the result pointer correctly. You need to know the service version, service class, event types, etc. - this would result in a gigantic factory creating Java objects for all data structures in all versions. And this factory only handles output parameters, you need to create input structures as well. That is also the main reason why you can't simply create a copy of WFSResult.
So I stick to the model of Struct classes using memory allocated from XFS and Java. For output parameters I can copy the data to Java memory, which makes it safe for application uses and I'm still able to create input structures without native code. Take CamStatus as an example of the way I will do things in future. So there is a base version of the class, say equal to XFS 3.00. And changes in newer versions will result in sub classes (CamStatusV3_20). The command (CamStatusCommand) is responsible for creating the right java object for the right xfs version, copy them to java memory and for freeing XFS allocated memory by calling WFSFreeResult.
The application who uses the command is then safe to handle the result in any way possible, it will be garbage collected when it's no longer needed. There are fewer calls to WFSFreeResult, so it will be harder to miss. I also want to move the (Xfs) struct classes further away from the Win32 data types and provide simple Java types as getter-results. The goal is to keep XFS specifics away from application developers.
And now to further answer you question, PTRRawDataCallable is a good example for the old way. It's currently used by PTRRawDataTask which resides in O2XfsOperator and frees the result - so no memory leak here but the application is responsible for freeing the result.
And the CASH_IN_START is an execute command, so you want event handling and a simple Callable isn't enough - so take a look at TakePictureCommand. Although its intended do deliver a result with data, you can always create a special case object like EmptyCompleteEvent in TakePictureCommand.
One last note, I work on porting CDM data structures to O2Xfs. I will pull when first tests are successful.
Best regards, Andreas
Dear @AndreasFagschlunger,
Thank you for your clear description now i understand what is going on under the hood, I'll check CASH_IN_START and i'll add event handling.thank you again. As you know i'm developing the CIM module, if you want i can give you my source code after the completion of development and testing.
Best Regards, Pouya
Dear Andreas,
I found out in this way that each time we call xfs command and get some result from DLLs we have to call free on XFS Service to release the allocated memory in DLL, am I right?
In some cases you've called the free function with wfsresult argument after cloning this object like call function of GetPINBlockCallable class and in another case you've returned the wfsresult directly without cloning it like call function of PTRRawDataCallable class, (isn't it a memory leak?)
In addition some command like wfs_cim_cash_in_start the out put parameter is none in the documentation, in the callable mode what should i do? should i return the wfsresult directly? or clone wfsresult via the constructor with pointer parameter?
with best regards, Pouya