Disable Undo system when possible

The undo system can consume large amounts of memory and slow down processing.

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.

undo

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