[Closed] weird crash/leak with scripted simpleObjs …
my guess is you have very tight dependency in your setup. it causes ‘all-time-every-time’ mesh build.
‘mesh build’ usually leaks. you can read about this fact in the mxs help and find about it on this forum.
i don’t really know what to suggest.
try to reuse snapped meshes. because a copy of trimesh is much cheaper than any new mesh snap.
I had literally not heard of that way of caching functions, Ill look into it more and try to implement it. (I guess you just make local variables of all the functions youre going to use? sounds easy but Ill look it up)
Yes, that’s it. It is somewhere in the MXS help I think.
But one thing I dont understand is if those vector operations are leaky, they should be leaky on every evaluation wouldnt they?
Yes, they should, although I don’t think this is your problem.
as for the parameters Im not sure what else I can do, I do need to reference these objects and object settings in parameters dont I? how else would they be saved with the object?
I would check if you are storing objects and updating them constantly and if any of the plugins parameters are tied to a monitor or controller that is making the BuilMesh() event fire up so frequently.
(funny thing is its caused a new problem where the interaction with the driving spline is not just slow (in fact its not) but its like double transformed, it accelerates away in both translate, rotate and scale…gaah. why cant things just work =D )
Whenever you see this behavior, you are near to a Max crash. Save and restart Max, I know no other way to reverse this issue.
Also, I don’t think you need to do a full gc(), just a light and perhaps delayed one, but I would leave that option as a last resource. I would first try to isolate the problem and solve it without calling gc(). Also, calling gc light:on will slow down the whole plugin, depending on where you use it, but sometimes it is needed.
As I see this, you have two problems, one is the memory leaking and the other one the constant call to BuildMesh(). The crash is perhaps related to the memory leak, moreover if it happens out of the MXS heap. And it just gets worse when there are so many updates. But you should fix both of them. The most important to me would be the memory leak.
Below there are a few tests you can run to see how a few things we have mentioned performs. While I don’t think it is just one thing what is causing the troubles, the combination of some of them can lead to very bad performance.
/* Methods caching test */
(
gc()
delete objects
obj = converttomesh (geosphere segs:32)
st = timestamp(); sh = heapfree
for j = 1 to 100 do
(
for j = 1 to obj.numfaces do meshop.getfacecenter obj j
)
format "time:% ram:%
" (timestamp()-st) (sh-heapfree)
st = timestamp(); sh = heapfree
GetFaceCenter = meshop.getfacecenter -- Keeps memory low
for j = 1 to 100 do
(
for j = 1 to obj.numfaces do GetFaceCenter obj j
)
format "time:% ram:%
" (timestamp()-st) (sh-heapfree)
)
/* SnapshotAsMesh() test */
(
delete objects
obj = converttomesh (geosphere segs:64)
messagebox "Watch out the System Memory!
It will go up around 3.5GB."
gc()
st = timestamp(); sh = heapfree
for j = 1 to 1000 do
(
tmesh = snapshotasmesh obj
)
format "time:% ram:%
" (timestamp()-st) (sh-heapfree)
messagebox "Watch out the System Memory!"
gc()
st = timestamp(); sh = heapfree
for j = 1 to 1000 do
(
tmesh = snapshotasmesh obj
free tmesh -- Keeps memory low
)
format "time:% ram:%
" (timestamp()-st) (sh-heapfree)
)
/* Copy node mesh test */
(
delete objects
obj = converttomesh (geosphere segs:64)
messagebox "Watch out the System Memory!
It will go up around 3.5GB."
gc()
st = timestamp(); sh = heapfree
for j = 1 to 1000 do
(
tmesh = copy obj.mesh
)
format "time:% ram:%
" (timestamp()-st) (sh-heapfree)
messagebox "Watch out the System Memory!"
gc()
st = timestamp(); sh = heapfree
for j = 1 to 1000 do
(
tmesh = copy obj.mesh
free tmesh -- Keeps memory low
)
format "time:% ram:%
" (timestamp()-st) (sh-heapfree)
)
/* Copy node baseobject test */
(
delete objects
obj = converttomesh (geosphere segs:64)
messagebox "Watch out the System Memory!
It will go up around 3.5GB."
gc()
st = timestamp(); sh = heapfree
for j = 1 to 1000 do
(
tmesh = copy obj.baseobject
)
format "time:% ram:%
" (timestamp()-st) (sh-heapfree)
messagebox "Watch out the System Memory!"
gc()
st = timestamp(); sh = heapfree
for j = 1 to 1000 do
(
tmesh = copy obj.baseobject
free tmesh -- DOES NOT keep memory low. Full GC() needed. No guarantees though.
)
format "time:% ram:%
" (timestamp()-st) (sh-heapfree)
)
/* Point3 test */
(
gc()
st = timestamp(); sh = heapfree
pt = [1,1,1]
for j = 1 to 1000000 do
(
pt *= [2,3,4]
)
format "time:% ram:%
" (timestamp()-st) (sh-heapfree)
st = timestamp(); sh = heapfree
pt = [1,1,1]
for j = 1 to 1000000 do
(
pt.x *= 2
pt.y *= 3
pt.z *= 4
)
format "time:% ram:%
" (timestamp()-st) (sh-heapfree)
)
Bear in mind that the ‘Point3 test’ might make you even more confused (at least with newer versions of max; not sure if it’s a good idea to take max 9 results into account). Cf:
(
fn doSomething val = return val
gc(); st = timeStamp(); sh = heapFree
for i = 1 to 1000000 do ()
format "do nothing time:% heap:%
" (timeStamp() - st) (sh - heapFree)
pt = [1,1,1]
mult = [1.00001,1.00002,1.00003] -- didn't want 1.#INF from 127th iteration on...
gc(); st = timeStamp(); sh = heapFree
for i = 1 to 1000000 do doSomething (pt * mult)
format "vectorMathFn time:% heap:%
" (timeStamp() - st) (sh - heapFree)
pt = [1,1,1]
mult = [1.00001,1.00002,1.00003]
gc(); st = timeStamp(); sh = heapFree
for i = 1 to 1000000 do local newVar = pt * mult
format "vectorMathLocal time:% heap:%
" (timeStamp() - st) (sh - heapFree)
pt = [1,1,1]
mult = [1.00001,1.00002,1.00003]
gc(); st = timeStamp(); sh = heapFree
for i = 1 to 1000000 do pt *= mult
format "vectorMathAssignment time:% heap:%
" (timeStamp() - st) (sh - heapFree)
pt = [1,1,1]
mult = [1.00001,1.00002,1.00003]
gc(); st = timeStamp(); sh = heapFree
for j = 1 to 1000000 do
(
pt.x *= 1.00001
pt.y *= 1.00002
pt.z *= 1.00003
)
format "perPartsAssignment time:% heap:%
" (timeStamp() - st) (sh - heapFree)
)
max 9 x86 (couldn't resist, still have an old non-upgradeable NFR version); heapSize 2^26 and more:
do nothing time:329 heap:64L
vectorMathFn time:1078 heap:64L
vectorMathLocal time:1015 heap:64L
vectorMathAssignment time:1047 heap:36028204L
perPartsAssignment time:2485 heap:64L
max 2016; heapSize 2^25:
do nothing time:282 heap:128L
vectorMathFn time:1406 heap:7452856L
vectorMathLocal time:1930 heap:103160L
vectorMathAssignment time:1780 heap:103032L
perPartsAssignment time:5204 heap:10715432L
max 2016; heapSize 2^26:
do nothing time:283 heap:128L
vectorMathFn time:1266 heap:14731112L
vectorMathLocal time:1559 heap:25711216L
vectorMathAssignment time:1423 heap:25712208L
perPartsAssignment time:4380 heap:15109200L
max 2016; heapSize 2^27:
do nothing time:282 heap:128L
vectorMathFn time:1116 heap:61987752L
vectorMathLocal time:1704 heap:5791352L
vectorMathAssignment time:1569 heap:5791776L
perPartsAssignment time:4221 heap:49422848L
max 2016; heapSize 2^28:
do nothing time:281 heap:128L
vectorMathFn time:1095 heap:61987736L
vectorMathLocal time:1080 heap:120088384L
vectorMathAssignment time:912 heap:120088408L
perPartsAssignment time:3763 heap:143677744L
max 2016; heapSize 2^29 and more:
do nothing time:276 heap:128L
vectorMathFn time:1107 heap:61987712L
vectorMathLocal time:1075 heap:120088352L
vectorMathAssignment time:888 heap:120088376L
perPartsAssignment time:2953 heap:392131672L
The same in reverse order of execution:
max 2016; heapSize 2^25:
perPartsAssignment time:2687 heap:8252424L
vectorMathAssignment time:1779 heap:102776L
vectorMathLocal time:1953 heap:102336L
vectorMathFn time:2142 heap:102392L
do nothing time:760 heap:1522232L
max 2016; heapSize 2^26:
perPartsAssignment time:2460 heap:20225992L
vectorMathAssignment time:1383 heap:33899448L
vectorMathLocal time:1536 heap:33899544L
vectorMathFn time:1720 heap:33899544L
do nothing time:598 heap:12957272L
max 2016; heapSize 2^27:
perPartsAssignment time:2123 heap:106304048L
vectorMathAssignment time:1511 heap:9833496L
vectorMathLocal time:1646 heap:9833640L
vectorMathFn time:1886 heap:9833608L
do nothing time:427 heap:55996192L
max 2016; heapSize 2^28:
perPartsAssignment time:2122 heap:106303912L
vectorMathAssignment time:888 heap:119985336L
vectorMathLocal time:1029 heap:119985296L
vectorMathFn time:1229 heap:119985288L
do nothing time:428 heap:55996256L
max 2016; heapSize 2^29:
perPartsAssignment time:2126 heap:106303992L
vectorMathAssignment time:883 heap:119985336L
vectorMathLocal time:1031 heap:119985304L
vectorMathFn time:1224 heap:119985288L
do nothing time:426 heap:55996320L
Run one by one (max 2016; heapSize 2^29)
do nothing time:283 heap:128L
vectorMathFn time:1079 heap:61956904L
vectorMathLocal time:870 heap:61957376L
vectorMathAssignment time:758 heap:64004936L
perPartsAssignment time:2084 heap:106303880L
Run in pairs with the empty loop (max 2016; heapSize 2^29):
vectorMathFn time:1080 heap:61957344L
do nothing time:426 heap:55996688L
vectorMathLocal time:870 heap:61957344L
do nothing time:426 heap:55996680L
vectorMathAssignment time:754 heap:64004904L
do nothing time:281 heap:64L
perPartsAssignment time:2090 heap:106302936L
do nothing time:427 heap:55995944L
Sooo… if you’d look at these results first, what would be your conclusion?
this test proves that using of ny-component assignment is slower but cheaper for memory use.
count = 5000000
(
gc()
st = timeStamp()
sh = heapFree
pt = [1,1,1]
for j = 1 to count do
(
pt *= [1,2,3]
if (mod j 100000) == 0 do format " %
" (sh - heapFree)
)
format "use point3 time:% heap:%
" (timeStamp() - st) (sh - heapFree)
gc()
pt = [1,1,1]
st = timeStamp()
sh = heapFree
for j = 1 to count do
(
pt.x *= 1.000001
pt.y *= 2.000001
pt.z *= 3.000001
if (mod j 100000) == 0 do format " %
" (sh - heapFree)
)
format "components time:% heap:%
" (timeStamp() - st) (sh - heapFree)
)
we have an opposite result in some tests above but they tells only that in some situation gc() doesn’t work in local scope.
if you break it like:
count = 5000000
gc()
(
st = timeStamp()
sh = heapFree
pt = [1,1,1]
for j = 1 to count do
(
pt *= [1,2,3]
if (mod j 100000) == 0 do format " %
" (sh - heapFree)
)
format "use point3 time:% heap:%
" (timeStamp() - st) (sh - heapFree)
)
gc()
(
pt = [1,1,1]
st = timeStamp()
sh = heapFree
for j = 1 to count do
(
pt.x *= 1.000001
pt.y *= 2.000001
pt.z *= 3.000001
if (mod j 100000) == 0 do format " %
" (sh - heapFree)
)
format "components time:% heap:%
" (timeStamp() - st) (sh - heapFree)
)
the gc() has to work as expected
by using by-component assignment we try to avoid creation a new point3 every time when we assign full point3 value which causes the leaking
Yet the culprit seems to be the assignment of a new value to the existing Point3 value in the multiplication assignment within the for-loop. You will get the exact same result if you replace pt *= [1,2,3] with pt = [1,2,3]. On the other hand if you explicitly create a new local in the loop scope like local newLocal = pt * [1,2,3], it will be all okay. All in all, if you don’t need to change that one value multiple times, there’s no reason to do vector math by component.
Btw. just for fun, first without running it – which of these functions would you expect to leak:
fn fun1 = (local x = x_axis * 10)
fn fun2 = (local x = x_axis; x *= 10)
fn fun3 = (local x = x_axis; mult &x) -- where fn mult &x = x *= 10
fn fun4 = (local x = x_axis; x = mult x) -- where fn mult x = x * 10
fn fun5 = (local x = x_axis; do x *= 10 while 0 > 1)
fn fun6 = (local x = x_axis; for i = 1 to 1 do x * 10)
fn fun7 = (local x = x_axis; for i = 1 to 1 do x *= 10)
Hint: what the for loop does and while loop does not?
jorge, thanks for all the advice. youre an absolute trooper.
Aha, I see now what you meant about the parameters. But I dont think that was ever the problem (could be wrong) – Ive occasionally caused those kind of update loops and theyre very obvious when they occur since they immediately start looping and at a constant pace.
Having updated all my objects to replace the snapshots, that crashing issue is gone! Im not sure how stable it is (apparently I lied about the occasional bounding box flickering (and set key button) being gone, that still happens sometimes – often in conjunction with object creation etc)
But. progress has been made. thanks ever so much!