Notifications
Clear all

[Closed] Memory management issues

I have a function that assigns materials to imported meshs, either via loading a material library or a function loaded from an external script file. But, every time its run the overall script gets slower, until max needs to be restarted for it to work correctly anymore.

  I have absolutely no idea what is causing the memory leak, but maybe something will stand out to someone here?

      fn matPresets_fn objFullPath opacChec matPresetSel = (
	importedMeshs = getCurrentSelection() --newly imported objects, Max already selected them.
	
	--Load .mat preset into memory--
	MatPresetFullPath = (((systemTools.getEnvVariable("USERPROFILE"))+"\Documents\Applink_Max3DC\\") + matPresetSel)
	presetFileType = getFilenameType MatPresetFullPath
	
	--Loat .ms preset function into memory--
	firstLineOfMXS = #()
	if (presetFileType == ".ms") do (
		--read first line of preset file, find out the name of the function.
		mxsFile = openFile MatPresetFullPath mode:"r"
		firstLineOfMXS = (filterString (readLine mxsFile) "	, ")
		flush mxsFile
		close mxsFile
		fileIn MatPresetFullPath --loads the presets function into memory.
		)
	
	--Start--
	for curObj in importedMeshs do (
		curMatType = (classOf curObj.mat)
		
		loopLimit = 0
		if (curMatType == Standardmaterial) do (loopLimit = 2)
		if (curMatType == Multimaterial) do (loopLimit = ((curObj.mat.count)+1))
		
		subMatIndex = 1
		while subMatIndex != loopLimit do 
			(
			mapFullName = "" --Get the diffuse bitmap file name being used on the material/submaterial, then derive the core file name from it.
			if (curMatType == Standardmaterial) do (
				mapFullName = filenameFromPath (substituteString ((curObj.mat.diffuseMap.bitmap)as string) "BitMap:" ""))
			if (curMatType == Multimaterial) do (
				mapFullName = filenameFromPath (substituteString ((curObj.mat.materialList[subMatIndex].diffuseMap.bitmap)as string) "BitMap:" ""))
			mapFileType = getFilenameType mapFullName
			mapNameFront = substituteString mapFullName ("_color" + mapFileType) ""
			justThePath = (getFilenamePath objFullPath) --path minus the file itself.
			
			tdcDIFname = tdcROUname = tdcGLOname = tdcSPCname = tdcMETname = tdcNRMname = tdcEMname = tdcAOname = ""
			if (doesFileExist (justThePath + mapNameFront + "_color" + mapFileType)) 		do tdcDIFname = (mapNameFront + "_color" + mapFileType)
			if (doesFileExist (justThePath + mapNameFront + "_rough" + mapFileType))		 do tdcROUname = (mapNameFront + "_rough" + mapFileType)
			if (doesFileExist (justThePath + mapNameFront + "_gloss" + mapFileType))		 do tdcGLOname = (mapNameFront + "_gloss" + mapFileType)
			if (doesFileExist (justThePath + mapNameFront + "_specular_color" + mapFileType))	do tdcSPCname = (mapNameFront + "_specular_color" + mapFileType)
			if (doesFileExist (justThePath + mapNameFront + "_metalness" + mapFileType)) 		do tdcMETname = (mapNameFront + "_metalness" + mapFileType)
			if (doesFileExist (justThePath + mapNameFront + "_nmap" + mapFileType)) 		do tdcNRMname = (mapNameFront + "_nmap" + mapFileType)
			if (doesFileExist (justThePath + mapNameFront + "_emissive" + mapFileType)) 		do tdcEMname = (mapNameFront + "_emissive" + mapFileType)
			if (doesFileExist (justThePath + mapNameFront + "_ao" + mapFileType))			do tdcAOname = (mapNameFront + "_ao" + mapFileType)
				
			--We already have all the info we need, now to apply the new material(s)!
			if (presetFileType == ".mat") do 
				(
				tempLib = loadTempMaterialLibrary MatPresetFullPath --will just return undefined if not a .mat preset.
				if (curMatType == Standardmaterial) do (
					curObj.mat = tempLib[1] --convert the current material to the selected preset.
					for bmt in (getClassInstances bitmaptex target:(curObj.mat)) do (
						justTheName = filenameFromPath (bmt.filename)
						if (justTheName == "color.jpg") do 		(bmt.filename = (justThePath + tdcDIFname))
						--if (justTheName == "opacity.jpg") do 		(bmt.filename = (justThePath + tdcDIFname))
						if (justTheName == "rough.jpg") do 		(bmt.filename = (justThePath + tdcROUname))
						if (justTheName == "gloss.jpg") do 		(bmt.filename = (justThePath + tdcGLOname))
						if (justTheName == "specular_color.jpg") do 	(bmt.filename = (justThePath + tdcSPCname))
						if (justTheName == "metalness.jpg") do 		(bmt.filename = (justThePath + tdcMETname))
						if (justTheName == "normal.jpg") do 		(bmt.filename = (justThePath + tdcNRMname))
						if (justTheName == "emissive.jpg") do 		(bmt.filename = (justThePath + tdcEMname))
						if (justTheName == "ao.jpg") do 		(bmt.filename = (justThePath + tdcAOname))
						)
					)
				if (curMatType == Multimaterial) do (
					curObj.mat.materialList[subMatIndex] = tempLib[1] --convert the current material to the selected preset.
					for bmt in (getClassInstances bitmaptex target:(curObj.mat.materialList[subMatIndex])) do (
						justTheName = filenameFromPath (bmt.filename)
						if (justTheName == "color.jpg") do 		(bmt.filename = (justThePath + tdcDIFname))
						--if (justTheName == "opacity.jpg") do 		(bmt.filename = (justThePath + tdcDIFname))
						if (justTheName == "rough.jpg") do 		(bmt.filename = (justThePath + tdcROUname))
						if (justTheName == "gloss.jpg") do 		(bmt.filename = (justThePath + tdcGLOname))
						if (justTheName == "specular_color.jpg") do 	(bmt.filename = (justThePath + tdcSPCname))
						if (justTheName == "metalness.jpg") do 		(bmt.filename = (justThePath + tdcMETname))
						if (justTheName == "normal.jpg") do 		(bmt.filename = (justThePath + tdcNRMname))
						if (justTheName == "emissive.jpg") do 		(bmt.filename = (justThePath + tdcEMname))
						if (justTheName == "ao.jpg") do 		(bmt.filename = (justThePath + tdcAOname))
						)
					)
				tempLib = undefined
				GC()
				)
				
			if (presetFileType == ".ms") do 
				(
				global gbl_tdcDIFFUSE		= tdcDIFname
				global gbl_tdcROUGHNESS		= tdcROUname
				global gbl_tdcGLOSS		= tdcGLOname
				global gbl_tdcSPECOLOR		= tdcSPCname
				global gbl_tdcMETALNESS		= tdcMETname
				global gbl_tdcNORMAL		= tdcNRMname
				global gbl_tdcEMISSIVE		= tdcEMname
				global gbl_tdcAO		= tdcAOname
				global gbl_curMatType		= curMatType
				global gbl_curMatSubIndex	= subMatIndex
				global gbl_matOpacityEnabled	= opacChec
				global gbl_filePathOnly		= justThePath
				global gbl_curMesh		= curObj
				
				execute (firstLineOfMXS[2] + "()")
				)
			subMatIndex+=1
			)
		)
	)
      
5 Replies

you load a temp material library many times in your code but free it only one time at the end.

also i don’t see any reason to load it every time for every object.

the code needs total cleanup. there are too much unnecessary moves those don’t make memory using safer.

Ok, changed it so the temporary material library is cleaned after each loop. A new copy needs to be created each time to avoid the materials all being linked as instances to each other.
I’m not really sure what you mean by a “total cleanup” though?

This is the first time I’ve ever experienced memory issues in a script (lucky me I guess), so I’m more or less clueless when it comes to this sort of thing.

for example:

for node in allTheMaps do (
	if node == (justThePath + mapNameFront + "_color" + mapFileType) 			do tdcDIFname = (mapNameFront + "_color" + mapFileType)
	if node == (justThePath + mapNameFront + "_rough" + mapFileType)			 do tdcROUname = (mapNameFront + "_rough" + mapFileType)
	if node == (justThePath + mapNameFront + "_gloss" + mapFileType)			 do tdcGLOname = (mapNameFront + "_gloss" + mapFileType)
	if node == (justThePath + mapNameFront + "_specular_color" + mapFileType)	do tdcSPCname = (mapNameFront + "_specular_color" + mapFileType)
	if node == (justThePath + mapNameFront + "_metalness" + mapFileType) 		do tdcMETname = (mapNameFront + "_metalness" + mapFileType)
	if node == (justThePath + mapNameFront + "_nmap" + mapFileType) 			do tdcNRMname = (mapNameFront + "_nmap" + mapFileType)
	if node == (justThePath + mapNameFront + "_emissive" + mapFileType) 		do tdcEMname = (mapNameFront + "_emissive" + mapFileType)
	if node == (justThePath + mapNameFront + "_ao" + mapFileType)				do tdcAOname = (mapNameFront + "_ao" + mapFileType)
)

if first condition is TRUE why do you check all next? you do it for all meshes.
every condition creates new string and system doesn’t free these strings until the end of the function.

Well I can’t be sure which maps of the available ones users are exporting, so doing it that way serves the same purpose as running a ‘doesFileExist’ on each.
I figured going over the list of file names in an array one by one would be faster, but doesFileExist wouldn’t use as much memory…guess I’ll change that then.

Anyhow, memory issue seems to be solved now (seems to have been due to the improperly placed garbage collection). Thanks for the help!

Seems I was wrong.

Memory is still leaking when loading .ms files (issue with fileIn or maybe the global variables?). Loading regular material libraries is MUCH better now, but there’s still a very small leak that starts to become noticeable after a few dozen imports (though this might be an inherent leak in max2016 itself given how many unique obj file imports have to be performed before it starts to become noticeable).