The undo system can consume large amounts of memory and slow down processing.
MAXScript commands run from Listener. Script Editor or Macro Script are run within an undo on context.
MAXScript commands run from scripted UI controls are not run within an undo on context.
Do not delete nodes with undo off, unless you also created the nodes with undo off and did not do anything to the node with undo on.
When working with meshes, you typically want to use meshop methods as they support undo/redo. But typically you do not want to store undo records for all operations in a loop, just the first and last.
When working with EPoly, you want to store undo records for all operations in a loop.
TEST CASE:
em = mesh() meshop_setvert = meshop.setvert fn test7 holdAll = ( local nVerts = getnumverts em for i = 1 to nVerts do with undo (holdAll or (i == 1 or i == nVerts)) meshop_setvert em i ([1,1,1]*i) )
FOR 100,000 ITERATIONS:
test7 true -- 85313 msec., 229 MB test7 false-- 7609 msec., 11 MB
Every operation that creates an undo record will cost time and memory as it will create internal copies of the changing objects to allow an undo later. When making multiple changes in a loop like for example attaching multiple objects together, the Undo system would attempt to create a single undo copy of each resulting object and might even run out of memory. Disabling Undo explicitly using the Undo off ()
context can help to speed up scripts significantly in such cases.
The following extreme example shows the difference. In both cases, 1000 boxes will be created using MAXScript and then attached to a single mesh using the attach function. In the first case, each attach call will generate by default an undo record. In the second case, the undo will be explicitly disabled.
EXAMPLE 1 - UNOPTIMIZED SCRIPT:
delete $Box*--delete any existing boxes box_array = #()--initialize an array for i = 1 to 1000 do--repeat 1000 times box_array[i] = box pos:[i*30,0,0]--create 1000 boxes st = timestamp()--get the start time in milliseconds main_box = convertToMesh box_array[1]--collapse the first box to mesh for i = 2 to 1000 do--go through all other boxes attach main_box box_array[i]--attach each box to the mesh et = timestamp()--stop the time print (et-st)--print the resulting time gc()--call Garbage Collection &endash; you will needed it!
On a 800MHz PC, the execution of the attaching part of the script took more than a minute mainly because the system run out of memory and the OS had to swap to disk. Memory usage for 3ds Max went up with about 300 MB!
EXAMPLE 2 - OPTIMIZED SCRIPT:
delete $Box* box_array = #() for i = 1 to 1000 do box_array[i] = box pos:[i*30,0,0] st = timestamp() undo off--the only difference - the undo (--has been turned off main_box = convertToMesh box_array[1] for i = 2 to 1000 do attach main_box box_array[i] )--end undo off et = timestamp() print (et-st) --call Garbage Collection - you will needed it!
On the same 800MHz machine, the execution of the attaching part of the script took only 3685 milliseconds, almost 20 times faster! There were no memory consumption changes visible in the Windows Task Manager.
Previous Tip
Disable Viewport Redraws when making changes to scene objects
Next Tip
Modify Panel can be slow -change to Create Panel when possible