[Closed] Memory Leaking When Copying BaseObject
The Heap keeps relatively low, the problem is the system memory.
Doing this operations without calling gc() can eat all the system RAM pretty quick, and we know Max don’t like to run out of RAM.
why do you need many instances created (cloned) in the loop?
try to save file or increase the heapsize. it might release the memory.
what happens… base object is an object which has a dependency connection (invisible probably for mxs (for refs.getdependents)). it makes it ‘lifetime’ for global scope.
only the object exactly knows what kind of dependency there. the system only asks: “do you have any?” the object answers: “yes”. ok … it’s protected. only the object knows how to delete itself in this case.
but when the system is doing some garbage collection it just in case sends all objects something like “maybe a time to delete yourself?”. and some objects see: “indeed! there is nothing to keep me in this world! i wanna die!!! ” . something like that
I don’t need them to be created in a loop. I just coded that example for those who wanted to give it a try. But creating them out of a loop behaves the same.
C’mon, I don’t want soup, I want ice-cream.
– Saving the file does not reclaim the memroy.
– Holding the file does not reclaim the memroy.
– Increasing the Heap size does not reclaim the memroy.
The only way I found is either [b]gc()[/b] or [b]clearundobuffer()[/b] followed by [b]gc light:on[/b] which is basically the same. Clearing the Undo Buffer works, even when there are no (visible) entries of the operation.
Could be. I can’t find any dependents of the copies.
It could be. Even though it is weird why calling cg() after the initial variable creation does solve the problem. The copies are still the same. It looks like a bug in the Garbage Collector or the Undo system.
When you get the chance , give this a try to see what I mean.
(
delete objects
source = converttopoly (geoSphere radius:50 segs:40)
mesh = copy source
gc()
sh = heapfree; ram = (sysinfo.getMAXMemoryInfo())[8]
for j = 1 to 25 do (copy mesh.baseobject; gc light:on)
format "heap:% RAM:% MB
" (sh-heapfree) (((sysinfo.getMAXMemoryInfo())[8]-ram)/1024.^2)
)
heap:264L RAM:4.28125 MB
(
delete objects
source = converttopoly (geoSphere radius:50 segs:40)
gc()
mesh = copy source
sh = heapfree; ram = (sysinfo.getMAXMemoryInfo())[8]
for j = 1 to 25 do (copy mesh.baseobject; gc light:on)
format "heap:% RAM:% MB
" (sh-heapfree) (((sysinfo.getMAXMemoryInfo())[8]-ram)/1024.^2)
)
heap:3376L RAM:205.449 MB
i’ve had a chance to look at max and play with sdk…
here is a mxs extension that fixes (i hope) the leaking issue. as i expected poly base was protected from collection by its dependency to somewhere (i don’t have a time to investigate to what).
so:
def_visible_primitive (deleteReferenceTarget, "deleteReferenceTarget");
Value* deleteReferenceTarget_cf(Value** arg_list, int count)
{
check_arg_count_with_keys(deleteReferenceTarget, 1, count);
ReferenceTarget* targ = arg_list[0]->to_reftarg();
if (targ)
{
BOOL refDeleted = key_arg_or_default(refDeleted, &true_value)->to_bool();
if (refDeleted)
{
targ->DeleteAllRefs();
targ->DeleteThis();
}
else
{
targ->MaybeAutoDelete();
}
return bool_value(ReferenceTarget::IsDeleted(targ));
}
return &undefined;
}
using:
(
gc() -- Just to not run out of RAM after several tests
delete objects
poly = converttopoly (geoSphere radius:50 segs:40)
mesh = converttomesh (geoSphere radius:50 segs:40)
-- gc() -- Uncomment to prevent the memory leaking
-- select #(poly, mesh) -- Uncomment after previous GC() and the memory leaking is back
-- POLY TEST ---------------------------------------------------------------------------
st = timestamp(); sh = heapfree
usedRAM = (sysinfo.getMAXMemoryInfo())[8]
local polyCopy = undefined
local meshCopy = undefined
with undo off for j = 1 to 200 do
(
polyCopy = copy poly.baseobject
deleteReferenceTarget polyCopy
--free polyCopy -- Do nothing
--polyCopy = undefined -- Do nothing
--gc light:on delayed:off -- Do nothing
)
-- gc() -- Uncomment ro reclaim all the used RAM so far
usedRAM = (sysinfo.getMAXMemoryInfo())[8] - usedRAM
format "POLY >> time:% heap:% RAM:% MB
" (timestamp()-st) (sh-heapfree) (usedRAM/1024.^2)
-- MESH TEST ---------------------------------------------------------------------------
st = timestamp(); sh = heapfree
usedRAM = (sysinfo.getMAXMemoryInfo())[8]
for j = 1 to 200 do
(
meshCopy = copy mesh.baseobject
free meshCopy -- Do nothing
meshCopy = undefined -- Do nothing
--gc light:on delayed:off -- Do nothing
)
-- gc() -- Uncomment ro reclaim all the used RAM so far
usedRAM = (sysinfo.getMAXMemoryInfo())[8] - usedRAM
format "MESH >> time:% heap:% RAM:% MB
" (timestamp()-st) (sh-heapfree) (usedRAM/1024.^2)
gc light:on
completeredraw()
)
result:
POLY >> time:1968 heap:30320L RAM:0.0 MB
MESH >> time:222 heap:-62456L RAM:272.254 MB
Thank you so much for your time Denis!
That’s what I thought doing in the end, a function to release the objects from memory.
Will investigate if I can add an option to the Free() method.
I couldn’t find what the dependencies are, but I suspect they may be related to the controllers, as you can animate a copy of the BaseObject in memory, and if you save it with the scene the animations will remain there.
Haven’t yet tested it, but I think it will work fine.
thank you too. it was very good catch. i used a temp clone of poly object in some of my tools. and i see now that it was leaking. i thought it was because of just a big mesh but as i see now it’s the issue you found (unreleased poly object).
so it’s exactly what this forum is about – help each other
Works great so far.
(
with undo off
(
delete objects
poly = converttopoly (geoSphere radius:50 segs:40)
ram = (sysinfo.getMAXMemoryInfo())[8]
polyCopy = copy poly.baseobject
format "isDeleted:% copyHandle:% %
" (isDeleted polyCopy) (getHandleByAnim polyCopy) polyCopy
deleteReferenceTarget polyCopy
format "isDeleted:% copyHandle:% %
" (isDeleted polyCopy) (getHandleByAnim polyCopy) polyCopy
format "RAM:% MB
" (((sysinfo.getMAXMemoryInfo())[8]-ram)/1024.^2)
)
gc light:on -- Needed to avoid memory leacking
)
– isDeleted:false copyHandle:16839P Editable Poly
– isDeleted:true copyHandle:0 <Deleted Max object>
– RAM:0.0 MB
but when the system is doing some garbage collection it just in case sends all objects something like “maybe a time to delete yourself?”. and some objects see: “indeed! there is nothing to keep me in this world! i wanna die!!! ” . something like that
it’s probably a simple “reference” counter, maintained in the base MaxHeapOperators Class , means object won’t/can’t be deleted unless the counter is zero.
Here are the dependencies:
(
delete objects
poly = converttopoly (geoSphere segs:6)
polyCopy = copy poly.baseobject
polyNumRef = refs.getNumRefs polyCopy
mesh = converttomesh (geoSphere segs:6)
meshCopy = copy mesh.baseobject
meshNumRef = refs.getNumRefs meshCopy
format "%
Dependencies:
" polyCopy
for j = 1 to polyNumRef do format " %
" (refs.getReference polyCopy j)
format "%
Dependencies:
" meshCopy
for j = 1 to meshNumRef do format " %
" (refs.getReference meshCopy j)
)
– Editable Poly
– Dependencies:
– ReferenceTarget:ParamBlock2
– ReferenceTarget:ReferenceTarget
– Editable Mesh
– Dependencies:
– ReferenceTarget:ReferenceTarget
Editable Poly
Dependencies:
ReferenceTarget:ParamBlock2
ReferenceTarget:MasterPointControlImp
OK