SceneKit: too much memory persisting

后端 未结 2 1900
悲哀的现实
悲哀的现实 2021-01-07 11:33

I’m out of ideas here, SceneKit is piling on the memory and I’m only getting started. I’m displaying SNCNodes which are stored in arrays so I can separate compo

相关标签:
2条回答
  • 2021-01-07 11:55

    I did also experience a lot of memory bloat from SceneKit in my app, with similar memory chunks as you in Instruments (C3DGenericSourceCreateDeserializedDataWithAccessors, C3DMeshSourceCreateMutable, etc). I found that setting the geometry property to nil on the SCNNode objects before letting Swift deinitialize them solved it.

    In your case, in you cleanup function, do something like:

    atomsNode_1.removeFromParentNode()
    atomsNode_1.geometry = nil
    atomsNode_2.removeFromParentNode()
    atomsNode_2.geometry = nil
    

    Another example of how you may implement the cleaning:

    class ViewController: UIViewController {
        @IBOutlet weak var sceneView: SCNView!
        var scene: SCNScene!
    
        // ...
    
        override func viewDidLoad() {
            super.viewDidLoad()
            scene = SCNScene()
            sceneView.scene = scene
    
            // ...
        }
    
        deinit {
            scene.rootNode.cleanup()
        }
    
        // ...
    }
    
    extension SCNNode {
        func cleanup() {
            for child in childNodes {
                child.cleanup()
            }
            geometry = nil
        }
    }
    

    If that doesn't work, you may have better success by setting its texture to nil, as reported on scene kit memory management using swift.

    0 讨论(0)
  • 2021-01-07 11:56

    Spheres, capsules, and cylinders all have fairly dense meshes. Do you need all that detail? Try reducing the various segment count properties (segmentCount, radialSegmentCount, etc). As a quick test, substitute SCNPyramid for all of your primitive types (that's the primitive with the lowest vector count). You should see a dramatic reduction in memory use if this is a factor (it will look ugly, but will give you immediate feedback on whether you're on a usable track). Can you use a long SCNBox instead of a cylinder?

    Another optimization step would be to use SCNLevelOfDetail to allow substitute, low vertex count geometry when an object is far away. That would be more work than simply reducing the segment counts uniformly, but would pay off if you sometimes need greater detail.

    Instead of managing the components yourself in arrays, use the node hierarchy to do that. Create each molecule, or animatable piece of a molecule, as a tree of SCNNodes. Give it a name. Make a flattenedClone. Now archive that. Read the node tree from archive when you need it; don't worry about arrays of nodes.

    Consider writing two programs. One is your iOS program that manipulates/displays the molecules. The other is a Mac (or iOS?) program that generates your molecule node trees and archives them. That will give you a bunch of SCNNode tree archives that you can embed, as resources, in your display program, with no on-the-fly generation.

    An answer to scene kit memory management using swift notes the need to nil out "textures" (materials or firstMaterial properties?) to release the node. Seems worth a look, although since you're just using UIColor I doubt it's a factor.

    Here's an example of creating a compound node and archiving it. In real code you'd separate the archiving from the creation. Note also the use of a long skinny box to simulate a line. Try a chamfer radius of 0!

    extension SCNNode {
    
    public class func gizmoNode(axisLength: CGFloat) -> SCNNode {
        let offset = CGFloat(axisLength/2.0)
        let axisSide = CGFloat(0.1)
        let chamferRadius = CGFloat(axisSide)
    
        let xBox = SCNBox(width: axisLength, height: axisSide, length: axisSide, chamferRadius: chamferRadius)
        xBox.firstMaterial?.diffuse.contents = NSColor.redColor()
        let yBox = SCNBox(width: axisSide, height: axisLength, length: axisSide, chamferRadius: chamferRadius)
        yBox.firstMaterial?.diffuse.contents = NSColor.greenColor()
        let zBox = SCNBox(width: axisSide, height: axisSide, length: axisLength, chamferRadius: chamferRadius)
        zBox.firstMaterial?.diffuse.contents = NSColor.blueColor()
        let xNode = SCNNode(geometry: xBox)
        xNode.name = "X axis"
        let yNode = SCNNode(geometry: yBox)
        yNode.name = "Y axis"
        let zNode = SCNNode(geometry: zBox)
        zNode.name = "Z axis"
    
        let result = SCNNode()
        result.name = "Gizmo"
        result.addChildNode(xNode)
        result.addChildNode(yNode)
        result.addChildNode(zNode)
        xNode.position.x = offset
        yNode.position.y = offset
        zNode.position.z = offset
    
        let data = NSKeyedArchiver.archivedDataWithRootObject(result)
        let filename = "gizmo"
    
        // Save data to file
        let DocumentDirURL = try! NSFileManager.defaultManager().URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: true)
    
        // made the extension "plist" so you can easily inspect it by opening in Finder. Could just as well be "scn" or "node"
        // ".scn" can be opened in the Xcode Scene Editor
        let fileURL = DocumentDirURL.URLByAppendingPathComponent(filename).URLByAppendingPathExtension("plist")
        print("FilePath:", fileURL.path)
    
        if (!data.writeToURL(fileURL, atomically: true)) {
            print("oops")
        }
        return result
    }
    }   
    
    0 讨论(0)
提交回复
热议问题