From: William S F. <ws...@fu...> - 2013-01-29 06:52:43
|
On 28/01/13 21:52, William S Fulton wrote: > On 25/01/13 23:41, Eric Wing wrote: >> On 1/25/13, William S Fulton <ws...@fu...> wrote: >>> On 23/01/13 08:29, Eric Wing wrote: >>>> Sorry if some of you have already seen this, but I'm struggling with >>>> %newobject and %delobject. I can't tell if the problem is if I'm >>>> misusing and misunderstanding them or if there is an actual bug. My >>>> expectation is in garbage collected languages, the %delobject function >>>> should automatically be invoked when all references to an object are >>>> removed and the garbage collector kicks in. >>>> >>>> >>>> In my reduced test case, I have 2 C functions that load sound handles >>>> (malloc) and a function that deletes them. In my .i file, I declare >>>> them like so: >>>> >>>> %newobject ALmixer_LoadAll; >>>> %newobject ALmixer_LoadStream; >>>> %delobject ALmixer_FreeData; >>>> extern ALmixer_Data* ALmixer_LoadAll(const char* file_name); >>>> extern ALmixer_Data* ALmixer_LoadStream(const char* file_name); >>>> extern void ALmixer_FreeData(ALmixer_Data* almixer_data); >>>> >>>> I started with the JavaScriptCore generator but never saw anything get >>>> collected. So with the Lua generator, I repeated the same test and >>>> know I can force garbage collection by calling >>>> collectgarbage("collect"). >>>> >>>> Basically my test script is: >>>> sound = ALmixer.LoadAll("test.wav") >>>> sound = nil >>>> collectgarbage("collect") >>>> >>>> I expect my ALmixer.FreeData function to be called when the object is >>>> collected. My FreeData function prints a message to let me know if it >>>> was called. It is not called. >>>> >>> I don't know about the Javascript module as it isn't in the mainline >>> SWIG distribution, however, this works in languages like Python. I think >>> that given the Javascript module is not fully ready for release, you're >>> best to compare behaviour with a known working language module to >>> determine if the problem is in your SWIG directives or in the >>> implementation of the language module. Did you check to see if the >>> generated code changes with or without the %newobject/%delobject? It >>> should. >>> >>> The implementation for each language module is slightly different, but a >>> call to >>> >>> GetFlag(n, "feature:new") >>> >>> would indicate it has been implemented in the Source/Modules/xxx.cxx >>> file, where xxx is the language module implementation file, something >>> like javascript.cxx. >>> >>> William >>> >> >> So based on some private replies I got, I now believe I misunderstood >> what %delobject actually does. %delobject marks the SWIG proxy object >> so if you manually free it using exposed API functions, and the object >> later gets garbage collected by the system, SWIG will avoid double >> freeing it. >> >> But returning to the question, "Why isn't SWIG invoking my free >> function when the object is collected?", it seems that >> %newobject/%delobject do not actually set a mapping between the Create >> and Free functions. All they seem to do is inform SWIG about the >> current reference count of objects to avoid the double-free problem >> mentioned above. >> >> >> So I didn't try Python, but I did try Lua (because I understand the >> Lua-C API a bit better and can analyze that generated code output and >> there is an explicit function I can call in Lua to force garbage >> collection immediately for easy testing/debugging). My test code in >> Lua showed this exact same problem as I described with the >> JavaScriptCore generator. >> >> Using %newobject/%delobject does in fact generate slightly different >> code in the Lua generator so it is in fact implemented. >> >> So as a newcomer, this seems very odd/strange/deficient that SWIG >> would have all this infrastructure for memory management and yet >> doesn't clean up after itself. So I looked at the generated code in a >> little more detail. >> >> In Lua, you have the ability to register a metamethod called "__gc" >> which lets you define a C function to be invoked to handle any clean >> up. If you set this up, when your object gets collected, that callback >> fires. Typically, this is where you would call your Free function for >> the stuff that the SWIG proxy is wrapping. >> >> SWIG does in fact seem to have code for __gc. (The code is a little >> complicated and there is some indirection/nesting in the metatable >> which confuses me so I don't fully understand how it works yet.) But >> for my case, this code is not reached for my case so my objects are >> leaking. I think what is going on is that SWIG only sets this code up >> if the objects being wrapped are C++ classes with destructors that can >> be invoked. In my case, I am dealing with a plain old C struct, not a >> C++ class so there is no destructor. So SWIG is leaking my object and >> I don't seem to have a way to tell SWIG explicitly that the >> "destructor" in this case is my ALmixer_Free function. I thought >> %delobject would set up this mapping, but it doesn't seem to be the >> case (unless this is different for other language generators, but >> neither Lua nor JSCore worked so far). >> > Ah right I see, yes, %delobject isn't right for what you want. What you > want are constructor and destructor type functionality for C structs. > This is covered in the Basics chapter: > file:///home/william/swig/github/swig/Doc/Manual/SWIG.html#SWIG_adding_member_functions > Sorry, I meant to give the online URL: http://www.swig.org/Doc2.0/SWIG.html#SWIG_adding_member_functions William |