View Issue Details

IDProjectCategoryView StatusLast Update
0003191FreeCADBugpublic2017-10-18 12:11
ReporterKarenRei Assigned Towmayer  
PrioritynormalSeveritymajorReproducibilityalways
Status closedResolutionfixed 
Product Version0.17 
Fixed in Version0.17 
Summary0003191: Readily reproducible memory leak - FreeCAD doesn't reclaim memory on object deletion / project close.
DescriptionAs in the summary. Deleting objects and closing projects doesn't free memory. Eventually FreeCAD will run the system out of memory when you keep repeating the same workflow.
Steps To Reproduce1. Save the attached .dae file in /tmp
2. Run the attached python workflow in the console (you'll see some errors at the end due to a different bug related to unicode, but they don't matter)
3. Note the memory usage in top.
4. Close the project (without closing FreeCAD) and go back to step 2.

Each time, on my system at least, it consumes an additional ~ 10% memory. And right now I'm using a rather simplified model.

In addition to closing projects not freeing memory, manually deleting individual objects doesn't appear to free memory either. The only thing that ever seems to get the memory back is closing and restarting FreeCAD.
Additional InformationOS: "Fedora release 24 (Twenty Four)"
Word size of OS: 64-bit
Word size of FreeCAD: 64-bit
Version: 0.17.12122 (Git)
Build type: Unknown
Branch: master
Hash: 501729a84cd0aeef0ae2fcf24cc832eafaf0fa13
Python version: 2.7.13
Qt version: 4.8.7
Coin version: 3.1.3
OCC version: 6.8.0.oce-0.17
Locale: Icelandic/Iceland (is_IS)
Tagsmemory leak
FreeCAD Information

Relationships

related to 0003025 closedwmayer Unhandled unknown exception caught in GUIApplication::notify when opening file + memory leak 

Activities

KarenRei

2017-09-17 15:12

reporter  

tmp.dae (57,287 bytes)
fem.py (7,235 bytes)   
import importDAE, Part, ObjectsFem, Fem, FemGmshTools, FemGui, FemToolsCcx

PRESSURE_MODE = 1
MAX_DEPTH = 8.0
HEIGHT = 6.48
GROUND_DENSITY = 1500.0
GMSH_RES_METERS = 2.0
PRESSURE_LAYERS = 100

importDAE.open(u"/tmp/tmp.dae")
doc = FreeCAD.getDocument("tmp")
gui_doc = Gui.getDocument("tmp")
mesh = doc.getObject("Mesh")
ground = doc.getObject("Mesh001")
Gui.SendMsgToActiveView("ViewFit")

print "Object loaded.  Making shape..."
part = doc.addObject("Part::Feature", "Hús part")
shape_tmp = Part.Shape()
shape_tmp.makeShapeFromMesh(mesh.Mesh.Topology, 0.100000)
part.Shape = shape_tmp
part.purgeTouched()
delete shape_tmp

# solidify
print "Solidifying..."
solid_tmp = part.Shape
solid_tmp = Part.Solid(solid_tmp)
solid_part = doc.addObject("Part::Feature", "Hús solid part")
solid_part.Label = "Hús solid part"
solid_part.Shape = solid_tmp
delete solid_tmp

# refining
print "Refining..."
refined_part = doc.addObject("Part::Feature", "Hús refined part")
refined_part.Shape = solid_part.Shape.removeSplitter()

# analysis
analysis_object = ObjectsFem.makeAnalysis("Analysis")
FemGui.setActiveAnalysis(doc.Analysis)

# gmsh
print "Computing gmsh..."
gmsh = ObjectsFem.makeMeshGmsh('Hús FEM')
gmsh.Part = refined_part
gmsh.CharacteristicLengthMax = 1000.0 * GMSH_RES_METERS
gmsh.CharacteristicLengthMin = 0.0
gmsh_mesh = FemGmshTools.FemGmshTools(gmsh)
error = gmsh_mesh.create_mesh()
print error
doc.Analysis.Member += [gmsh]
doc.recompute()

# solver
print "Creating solver..."
solver_object = ObjectsFem.makeSolverCalculix("CalculiX")
solver_object.GeometricalNonlinearity = 'linear'
solver_object.ThermoMechSteadyState = True
solver_object.MatrixSolverType = 'default'
solver_object.IterationsControlParameterTimeUse = False
doc.Analysis.Member = doc.Analysis.Member + [solver_object]

# material
print "Adding material..."
material_object = ObjectsFem.makeMaterialSolid("SolidMaterial")
mat = material_object.Material
mat['Name'] = "Pumicecrete"
mat['YoungsModulus'] = "5000 MPa"
mat['PoissonRatio'] = "0.17"
mat['Density'] = "1000 kg/m^3"
material_object.Material = mat
doc.Analysis.Member = doc.Analysis.Member + [material_object]

# bounding
print "Bounding..."
MIN_X =  9999999999999.9
MAX_X = -9999999999999.9
MIN_Y =  9999999999999.9
MAX_Y = -9999999999999.9
MIN_Z =  9999999999999.9
MAX_Z = -9999999999999.9
for vertex in refined_part.Shape.Vertexes:
  if vertex.X > MAX_X:
    MAX_X = vertex.X
  if vertex.X < MIN_X:
    MIN_X = vertex.X
  if vertex.Y > MAX_Y:
    MAX_Y = vertex.Y
  if vertex.Y < MIN_Y:
    MIN_Y = vertex.Y
  if vertex.Z > MAX_Z:
    MAX_Z = vertex.Z
  if vertex.Z < MIN_Z:
    MIN_Z = vertex.Z

SCALAR_X = MAX_X - MIN_X
SCALAR_Y = MAX_Y - MIN_Y
SCALAR_Z = (MAX_Z - MIN_Z) / HEIGHT


# fixed_constraint
print "Adding anchors..."
fixed_constraint = ObjectsFem.makeConstraintFixed("Anchors")
keys = []
for face_id in range(len(refined_part.Shape.Faces)):
  face = refined_part.Shape.Faces[face_id]
  z = (face.CenterOfMass.z - MIN_Z) / SCALAR_Z
  if z < 2.7 and face.normalAt(0, 0)[2] < -0.9:
    keys.append( (refined_part, "Face%d" % (face_id + 1)) )

fixed_constraint.References = keys
doc.Analysis.Member = doc.Analysis.Member + [fixed_constraint]

def sign(p0, p1, p2):
  return (p0[0] - p2[0]) * (p1[1] - p2[1]) - (p1[0] - p2[0]) * (p0[1] - p2[1])

def point_in_triangle(p0, p1, p2, x, y):
  pt = (x, y)
  b1 = sign(pt, p0, p1) < 0.0
  b2 = sign(pt, p1, p2) < 0.0
  b3 = sign(pt, p2, p0) < 0.0
  return (b1 == b2) & (b2 == b3)

def distance(x0, y0, x1, y1):
  return ((x0-x1)**2 + (y0-y1)**2)**0.5

def ground_height(x, y):
  for facet in ground.Mesh.Facets:
    p = []
    for i in facet.Points:
      p.append( ((i[0] - MIN_X) / SCALAR_X, (i[1] - MIN_Y) / SCALAR_Y, (i[2] - MIN_Z) / SCALAR_Z) )
    if point_in_triangle(p[0], p[1], p[2], x, y):
      break
  d0 = distance(x, y, p[0][0], p[0][1])
  d1 = distance(x, y, p[1][0], p[1][1])
  d2 = distance(x, y, p[2][0], p[2][1])
  sum = (d0 + d1 + d2)
  z = (d0 * p[0][2] + d1 * p[1][2] + d2 * p[2][2]) / sum
#  print x, y, " : ", p[0][2], p[1][2], p[2][2], " : ", d0, d1, d2, " : ", z
  return z

print "Adding pressures..."

if PRESSURE_MODE:
  # pressure_constraint
  keys = []
  for i in range(PRESSURE_LAYERS):
    keys.append([])
  for face_id in range(len(refined_part.Shape.Faces)):
    face = refined_part.Shape.Faces[face_id]
    average_depth = 0.0
    for vertex in face.Vertexes:
      x = (vertex.X - MIN_X) / SCALAR_X
      y = (vertex.Y - MIN_Y) / SCALAR_Y
      z = (vertex.Z - MIN_Z) / SCALAR_Z
      ground_z = ground_height(x, y)
      depth = ground_z - z
#      print ground_z, z, depth
      if depth > 0:
        average_depth += depth
    average_depth /= len(face.Vertexes)
    if average_depth > 0.0:
#      print "Adding key: %d %f to %d" % (face_id + 1, average_depth, int(round(average_depth / MAX_DEPTH * len(keys))))
      keys[int(round(average_depth / MAX_DEPTH * len(keys)))].append( (refined_part, "Face%d" % (face_id + 1)) )

  for key_id in range(len(keys)):
    if len(keys[key_id]) == 0:
      continue
    depth = key_id * MAX_DEPTH / len(keys)
#    print "%d) Adding pressures for %f: " % (key_id, depth), keys[key_id]
    pressure = (9.81 * GROUND_DENSITY * depth) / 1000000.0
    pressure_constraint = ObjectsFem.makeConstraintPressure("Pressure %0.4f" % pressure)
    pressure_constraint.References = keys[key_id]
    pressure_constraint.Pressure = pressure
    pressure_constraint.Reversed = False
    doc.Analysis.Member = doc.Analysis.Member + [pressure_constraint]
    #break

else:
  # ATH: ekki tilbúið!
  for key_id in range(len(keys)):
    if len(keys[key_id]) == 0:
      continue
    depth = key_id * MAX_DEPTH / len(keys)
    force_per_m2 = (9.81 * GROUND_DENSITY * depth)
    m2_on_z = 0# ATH
    force = force_per_m2 / m2_on_z
    force_constraint = ObjectsFem.makeConstraintForce("Force %0.0f" % force)
    force_constraint.References = keys[key_id]
    force_constraint.Force = force
    force_constraint.Reversed = False
    force_constraint.Direction = (refined_part, [nafn]) # ATH
    doc.Analysis.Member = doc.Analysis.Member + [force_constraint]

print "Pressures added."

## View object
#femmesh_obj = doc.addObject('Fem::FemMeshObject', 'FEM view')
#femmesh_obj.FemMesh = gmsh
#doc.Analysis.Member = doc.Analysis.Member + [femmesh_obj]

# run the analysis
FemGui.setActiveAnalysis(doc.Analysis)
fea = FemToolsCcx.FemToolsCcx()
fea.update_objects()
message = fea.check_prerequisites()
if not message:
  fea.reset_all()
  fea.run()
  fea.load_results()
else:
  FreeCAD.Console.PrintError("Houston, we have a problem! {}\n".format(message))  # in report view
  print("Houston, we have a problem! {}\n".format(message))  # in python console

# run the analysis
for m in analysis_object.Member:
  if m.isDerivedFrom('Fem::FemResultObject'):
    result_object = m
    break

gui_doc.getObject("Mesh001").Visibility = False
gui_doc.getObject("Mesh").Visibility = False
gui_doc.getObject("Hús part").Visibility = False
gui_doc.getObject("Hús solid part").Visibility = False
gui_doc.getObject("Hús refined part").Visibility = False

gmsh.ViewObject.setNodeDisplacementByVectors(result_object.NodeNumbers, result_object.DisplacementVectors)
gmsh.ViewObject.applyDisplacement(10)



fem.py (7,235 bytes)   

Kunda1

2017-09-30 11:34

administrator   ~0010216

Added forum thread: https://forum.freecadweb.org/viewtopic.php?f=8&t=24692

wmayer

2017-10-18 12:11

administrator   ~0010316

Looks like the observed memory leak was caused by the tree view which is fixed now.

Issue History

Date Modified Username Field Change
2017-09-17 15:12 KarenRei New Issue
2017-09-17 15:12 KarenRei File Added: tmp.dae
2017-09-17 15:12 KarenRei File Added: fem.py
2017-09-30 11:27 Kunda1 Steps to Reproduce Updated
2017-09-30 11:28 Kunda1 Tag Attached: memory leak
2017-09-30 11:28 Kunda1 Tag Attached: #post-to-forum
2017-09-30 11:31 Kunda1 Summary Readily reproducable memory leak - FreeCAD doesn't reclaim memory on object deletion / project close. => Readily reproducible memory leak - FreeCAD doesn't reclaim memory on object deletion / project close.
2017-09-30 11:34 Kunda1 Note Added: 0010216
2017-09-30 11:34 Kunda1 Tag Detached: #post-to-forum
2017-09-30 11:36 Kunda1 Relationship added related to 0003025
2017-10-18 12:11 wmayer Assigned To => wmayer
2017-10-18 12:11 wmayer Status new => closed
2017-10-18 12:11 wmayer Resolution open => fixed
2017-10-18 12:11 wmayer Fixed in Version => 0.17
2017-10-18 12:11 wmayer Note Added: 0010316