I'm not sure where the malloc error is coming from, exactly, but you need
to call "finalizer", not "finalize". Also it should be run on the XMLNode
rather than the XMLElement.
The following example might help (at least, it doesn't crash!)
julia> n = new_textnode("s")
s
julia> finalizer(n, z::XMLNode -> begin
#ccall(:puts, Void, (Ptr{Uint8},),
"called finalizer\n") #uncomment to verify
ccall(dlsym(LightXML.libxml2,
:xmlFreeNode), Void, (Ptr{Void},), z.ptr);
end)
julia> n = nothing
julia> gc()
On Mon, Jan 26, 2015 at 11:50 AM, Robert Feldt <[email protected]>
wrote:
> I fixed the typo (should be finalizer and not finalize) and also had to
> import xmlFreeNode from the c lib but when I run I get:
>
> julia(56167,0x7fff7924c300) malloc: *** error for object 0x7f9a33b159c0:
> pointer being freed was not allocated
> *** set a breakpoint in malloc_error_break to debug
>
> so there is something more at play here. Appreciate ideas.
>
> Cheers,
>
> Robert
>
> Den måndag 26 januari 2015 kl. 17:43:04 UTC+1 skrev Robert Feldt:
>
>> Actually this diff better shows the proposed changes:
>>
>> https://github.com/robertfeldt/LightXML.jl/commit/
>> 238fbb5c41629e254088dfe7553a53c72bd5dffa
>>
>> Will test and see if it helps.
>>
>> /Robert
>>
>> Den måndag 26 januari 2015 kl. 17:36:47 UTC+1 skrev Robert Feldt:
>>>
>>> Ok, great. I'm not used to explicit mem management from Julia so
>>> appreciate feedback on proposed solution:
>>>
>>> function free(xelem::XMLElement)
>>> ccall(xmlFreeNode, Void, (Ptr{Void},), xelem.node.ptr)
>>> xelem.node.ptr = nullptr
>>> end
>>>
>>> since XMLElement type has a node::XMLNode attribute and the XMLNode type
>>> has a ptr::Xptr and free for XMLDocument uses xmlFreeDoc like so:
>>>
>>> function free(xdoc::XMLDocument)
>>> ccall(xmlFreeDoc, Void, (Ptr{Void},), xdoc.ptr)
>>> xdoc.ptr = nullptr
>>> end
>>>
>>> and then add free as finalizer in constructor for XMLElement like so:
>>>
>>> function XMLElement(node::XMLNode)
>>> if !is_elementnode(node)
>>> throw(ArgumentError("The input node is not an element."))
>>> end
>>> xelem = new(node)
>>> finalize(xelem, free)
>>> xelem
>>> end
>>>
>>> I will try this and see if it addresses my problems but would be great
>>> with input on this.
>>>
>>> Cheers,
>>>
>>> Robert
>>>
>>> Den måndag 26 januari 2015 kl. 15:49:14 UTC+1 skrev Isaiah:
>>>>
>>>> The underlying XMLNode needs to be freed using xmlFreeNode from libxml2:
>>>>
>>>> http://xmlsoft.org/html/libxml-tree.html#xmlFreeNode
>>>>
>>>> I don't think this is wrapped yet, but it should be straightforward to
>>>> add -- ideally, called via a finalizer so that the objects are freed
>>>> automatically when Julia decides they can be GC'd.
>>>>
>>>> On Mon, Jan 26, 2015 at 7:42 AM, Robert Feldt <[email protected]>
>>>> wrote:
>>>>
>>>>> Hi,
>>>>>
>>>>> Does anyone now how to free up the memory in a XMLElement object in
>>>>> LightXML.jl?
>>>>>
>>>>> LightXML.jl has a free(xdoc::XMLDocument) but no corresponding
>>>>> free(xelem::XMLElement). There are functions related to free in clib.jl in
>>>>> the package but no docs that I can find on how to use it. I tried to
>>>>> create
>>>>> an XMLDocument from the element and then free the document but mem still
>>>>> leaks. Help appreciated.
>>>>>
>>>>> Background/context/details:
>>>>>
>>>>> In another thread we found out that our problems with mem-leaks in a
>>>>> long-running optimization is probably due to the use of LightXML.jl. The
>>>>> latter seem to require manual free'ing of resources as of the current
>>>>> version. Basically our main loop is something like this:
>>>>>
>>>>> # Create a large number of XMLElement's (possibly deeply nested) with
>>>>> construct_element(name::String, content::Array{Any}) = begin
>>>>> xmlelement = new_element(name)
>>>>> for item in content
>>>>> if typeof(item) <: Main.XMLElement
>>>>> add_child(xmlelement, item)
>>>>> elseif typeof(item) <: (String,String)
>>>>> set_attribute(xmlelement, item[1], item[2])
>>>>> elseif typeof(item) <: String
>>>>> add_text(xmlelement, item)
>>>>> else
>>>>> @assert false
>>>>> end
>>>>> end
>>>>> xmlelement
>>>>> end
>>>>>
>>>>> # What we are optimizing is the length of the xml when printed as
>>>>> string so we evaluated this by looping over array of xml elements
>>>>> generated
>>>>> # by construct_element above and calling on each one (the replace is
>>>>> for taking away at least some of the whitespace which is not important):
>>>>> fitness(xml) = length(replace(string(xml), r">\s+<", "><"))
>>>>>
>>>>> Since the optimization algorithm calls fitness on 100K to several
>>>>> million xml elements per run when we compare several optimization
>>>>> algorithms to each other the mem expansion gets up to many gigs and
>>>>> eventually there is problems. It seems there is no free on XMLElement in
>>>>> LightXML.jl but there is a free for XMLDocument. We thus tried to change
>>>>> to
>>>>> this:
>>>>>
>>>>> free_xmlelement(xmlelem::XMLElement) = begin
>>>>> tempdoc = XMLDocument()
>>>>> set_root(tempdoc, xmlelem)
>>>>> free(tempdoc)
>>>>> end
>>>>> fitness_with_free(xml) = begin
>>>>> qv = length(replace(string(xml), r">\s+<", "><"))
>>>>> free_xmlelement(xml)
>>>>> qv
>>>>> end
>>>>>
>>>>> but it does not seem to help. We would appreciate any help/advice on
>>>>> this or how we can further debug it. The documentation for xmlFreeDoc in
>>>>> libxml2 (which is what is what LightXML.free(xdoc::XMLDocument) calls)
>>>>> says that it will recursively free the document. But maybe we are missing
>>>>> something.
>>>>>
>>>>> Thanks for any advice,
>>>>>
>>>>> Robert Feldt
>>>>>
>>>>
>>>>