UserData/UserDictionary

So I rely pretty heavily on these for embedding information into geometry, say with a custom command, so that I can read it later via a plugin. Most of the time it works. About a year ago I was using it a lot, for very realtime applications, but was running into memory access errors. I stopped for those cases, but I still use it for embedding persistent data.

I am working on a new command, which builds very large PolyCurves. Not insanely large, but say 50k segments. Each segment needs some custom data, and I prefer to embed it into the segment, and not as a very large dictionary or userdata object on the polycurve. I usually explode the curve later so I like to do it on the segment.

But it seems to be causing problems again. On smaller Polycurves it runs fine, but once it gets to larger ones, I always get a nullref error on the userdictionary. IE in VS when it tries to write to it, its actually null. On a whim I tried switching to userdata. This worked slightly better, meaning it makes it farther into the polycurve before crashing! Interestingly, the exception in the case of UserData was still the same, and when I open the properties of the segment in VS its the UserDictionary throwing nullref…presumably they rely on the same underlying “stuff”.

So I am stuck a bit. I am not writing a lot of data into the dict/userdata. In fact mem usage in profiling is flat. But as the error is in the C layer I really don’t know the cause. And as I said, same code works fine on smaller polycurves.

Is this simply a memory issue, IE I need more ram? I do a bit of development on a slower machine, just so I can catch things like this… I am sure on my 64 bit machine it would make it farther. Its really not making it very far though. Should I be thinking about caching techniques? The plan is to scale this up pretty massively. These curves could get very large…

Here’s some code just to illustrate. This makes it much farther than my code, given its so minimal, but still not too impressive. My machine errors out at about 5000 segments.

    protected override Result RunCommand(RhinoDoc doc, RunMode mode)
    {
        // TODO: complete command.
        PolyCurve pCrv = new PolyCurve();
        int size = 10000;
        double length = 50;
        Point3d startPt = Point3d.Origin;
        for(int i=0;i<size;i++)
        {
            double[] arrOne = new[] { 1.0 };
            double[] arrTwo = new[] { 1.0 };
            Curve myCrv = new LineCurve(startPt, new Point3d(startPt.X + length, startPt.Y, startPt.Z));
            myCrv.UserDictionary.Set("stuffOne",arrOne);
            myCrv.UserDictionary.Set("stuffTwo",arrTwo);
            pCrv.Append(myCrv);
            startPt.X += length;
        }
        doc.Objects.AddCurve(pCrv);

        return Result.Success;
   }

So its clearly just a memory thing…but I would appreciate any ideas. Would the approach of storing the data in the userData of the polycurve, instead of the segment, help? I routinely use arrays of pretty large objects with lengths in the 100k range, so its not an issue with certain things. I would go with Polyline class but I have some nurbcurve segments in the polycurve. I admit, I have never done any caching, but the idea of writing this to a file and then reading it back in doesn’t sound that absurd. I am actually just storing parameters and values along the curve.

My experience with UserDictionary is that when you make thousands of them, the code will always eventually crash the application. If I were you, I’d move away from attaching the data on the geometry objects, and store it as one piece of data on the plugin, referencing the Guid of the polycurve.

http://developer.rhino3d.com/api/RhinoCommonWin/html/M_Rhino_PlugIns_PlugIn_ShouldCallWriteDocument.htm
http://developer.rhino3d.com/api/RhinoCommonWin/html/M_Rhino_PlugIns_PlugIn_WriteDocument.htm
http://developer.rhino3d.com/api/RhinoCommonWin/html/M_Rhino_PlugIns_PlugIn_ReadDocument.htm

For what its worth, I am not able to repeat the issue here just running Windows 10 on a system with only 8GB.

Thanks to both for the info. I am running Win 8 with 4gb here(but again, it doesn’t seem to be hitting the memory, where as other parts of the code do, still without a crash though).

I already use document data to serialize the global plugin state, so if that is a better solution, I would be open to using it here.

@Dale I think this is related to

And

http://mcneel.myjetbrains.com/youtrack/issue/RH-eqere

@wes_mcgee_3d, can you try the Rhino WIP to confirm that the above issue has been fixed.

https://mcneel.myjetbrains.com/youtrack/issue/RH-31343

I will try it, unfortunately I haven’t been keeping up on my WIP development as much as I would like so it may take a while.

In the meantime, the approach of just storing this info within my plugin is working (Dictionary of <Guid, CustomData>) is working better, easily dealing with 50k segments. I was planning to use the same object derived from Rhino.DocObjects.Custom.UserData for this. However, when I try to serialize, I get an error “Rhino.DocObjects.Custom.UserData is not marked as serializable”. I also noticed this in the past when trying to serialize Rhino.Collections.ArchivableDictionary. Is there something I need to do differently to get those objects to serialize(other than the obvious of not inheriting from that base class)?

You need to put [Seralizable] class attribute.
Also, if necessary, provide custom serialization routines, although of you only use BCL components it should work without any custom code. For more info, see

https://msdn.microsoft.com/en-us/library/ty01x675(v=vs.110).aspx

Yes I have my class marked as Serializable, but since Rhino.DocObjects.Custom.UserData is not (and I inherit from this, as described in the userdata example) it throws an error. I guess my question is why is Rhino.DocObjects.Custom.UserData not marked as serializable? When you say BCL, what does that mean? Regardless my class is super basic, just three numbers.

1 Like

BCL- base class library, all classes that come with the .net framework.
Maybe you need to implement the ISerializable interface?