EaBIM

标题: 访问实体的几何数据时,抛出 SEHException错误(只有Release版出现) [打印本页]

作者: 萧闫子    时间: 2014-1-15 14:15
标题: 访问实体的几何数据时,抛出 SEHException错误(只有Release版出现)

上周处理了一个有趣的问题,与垃圾回收机制有关。当获取Revit中对象的几何信息,在一个函数来获得构件的Solid。然后在Caller中对solid包含的面进行遍历访问。加载运行编译的debug版时,没有问题,当用Release版时,出现SEHExpection异常。


    --AccessViolationException - Attempted to read or write protected memory. This is often an indication that other          memory is corrupt.


这个问题的本质是有关垃圾回收机制的。因为大家常常用到几何数据访问,这里给大家分享下产生的原因和修改方法。


源代码大概样子是这样的:

注:在你运行的时候不一定出现这个错误,与机器的资源,内存,计算过程等有关。


[TransactionAttribute(Autodesk.Revit.Attributes.TransactionMode.Manual)]
[RegenerationAttribute(Autodesk.Revit.Attributes.RegenerationOption.Manual)]
public class Lab1PlaceGroup : IExternalCommand
{
  public Result Execute(
    ExternalCommandData commandData,
    ref string message,
    ElementSet elements)
    {
      //Get application and document objects
      UIApplication uiApp = commandData.Application;
      Document doc = uiApp.ActiveUIDocument.Document;

      Transaction trans = new Transaction(doc, "ExComm");
      trans.Start();

      //Define a Reference object to accept the pick result.
      Reference pickedRef = null;

      //Pick an object
      Selection sel = uiApp.ActiveUIDocument.Selection;
      pickedRef = sel.PickObject(ObjectType.Element,
        "Please select a family instance");
      Element elem = pickedRef.Element;
      
      Options geoOptions = uiApp.Application.Create.NewGeometryOptions();
      SolidArray solids = new SolidArray();
      GeometryElement geoElement = elem.get_Geometry(geoOptions);

      //get the transformed solid elements
      GetSolids(geoElement, ref solids);

      SolidArrayIterator solidIter = solids.ForwardIterator();
      solidIter.Reset();
      FaceArray faces = null;
      while (solidIter.MoveNext())
      {
        faces = null;
        Autodesk.Revit.DB.Solid sol = solidIter.Current as Autodesk.Revit.DB.Solid;
        faces = sol.Faces;
        if (faces.Size > 0) //抛出 SEHException错误,没有规律的出现。
        {
          TaskDialog.Show("Get faces", "the solid has " + faces.Size.ToString() + "faces");
        }
      }

     
      trans.Commit();

      return Result.Succeeded;
    }

  public void GetSolids(GeometryElement geomElem, ref SolidArray solids)
  {
    foreach (Autodesk.Revit.DB.GeometryObject geomObj in geomElem.Objects)
    {

      Autodesk.Revit.DB.Solid solid = geomObj as Autodesk.Revit.DB.Solid;
      if (null != solid)
      {
        if (solid.Faces.Size > 0)
        {
          {
            solids.Append(solid);
            continue;
          }
        }
      }

      Autodesk.Revit.DB.GeometryInstance geomInst = geomObj as Autodesk.Revit.DB.GeometryInstance;
      if (null != geomInst)
      {
        Autodesk.Revit.DB.GeometryElement transformedGeomElem = geomInst.GetInstanceGeometry((geomInst.Transform);     
        GetSolids(transformedGeomElem, ref solids);
      }
    }
  }  
}


错误原因是solid对象从GetInstanceGeometry 函数返回的transformedGeomElem 中获得。当退出拷贝solid的GetSolids()函数回到主调用函数后,操作系统把GetInstanceGeometry 返回的transformedGeomElem 的内存回收了。这一垃圾回收,导致返回到主条用函数的solidArray失去了数据源数据。在debug版,所有的变量占用的内存收保护没有被释放掉,所以debug版运行正常。在Release版垃圾回收机制起作用,把有用的内存数据释放了。所以我们再访问时,这块内存被保护起来了。所以错误信息包含 Attempted to read or write protected memory。


解决办法有两个:


1. 把读取solid数据的代码放在遍历solid的代码后面,处于同一个函数中。这样可能transformedGeomElem 还不能释放。

2. 增加一个对象引用,指向返回的transformedGeomElem 对象,这样也不会释放,因为有人正引用它。


下面是修改后的代码。


[TransactionAttribute(Autodesk.Revit.Attributes.TransactionMode.Manual)]
[RegenerationAttribute(Autodesk.Revit.Attributes.RegenerationOption.Manual)]
public class Lab1PlaceGroup : IExternalCommand
{
  public Result Execute(
    ExternalCommandData commandData,
    ref string message,
    ElementSet elements)
  {
    //Get application and document objects
    UIApplication uiApp = commandData.Application;
    Document doc = uiApp.ActiveUIDocument.Document;

    Transaction trans = new Transaction(doc, "ExComm");
    trans.Start();

    //Define a Reference object to accept the pick result.
    Reference pickedRef = null;

    //Pick an object
    Selection sel = uiApp.ActiveUIDocument.Selection;
    pickedRef = sel.PickObject(ObjectType.Element,
      "Please select a family instance");
    Element elem = pickedRef.Element;

    Options geoOptions = uiApp.Application.Create.NewGeometryOptions();
    SolidArray solids = new SolidArray();
    GeometryElement geoElement = elem.get_Geometry(geoOptions);

    GeometryElement refGeometry = null;  //对象保护,防止几何数据被释放掉了,后面产生SEHException.
    //get the transformed solid elements
    GetSolids(geoElement, ref solids,ref refGeometry);

    SolidArrayIterator solidIter = solids.ForwardIterator();
    solidIter.Reset();
    FaceArray faces = null;
    while (solidIter.MoveNext())
    {
      faces = null;
      Autodesk.Revit.DB.Solid sol = solidIter.Current as Autodesk.Revit.DB.Solid;
      faces = sol.Faces;
      if (faces.Size > 0) //这里再也不会出现问题了。
      {
        TaskDialog.Show("Get faces", "the solid has " + faces.Size.ToString() + "faces");
      }
    }


    trans.Commit();

    return Result.Succeeded;
  }

  public void GetSolids(GeometryElement geomElem, ref SolidArray solids, ref GeometryElement refGeometry)
  {
    foreach (Autodesk.Revit.DB.GeometryObject geomObj in geomElem.Objects)
    {

      Autodesk.Revit.DB.Solid solid = geomObj as Autodesk.Revit.DB.Solid;
      if (null != solid)
      {
        if (solid.Faces.Size > 0)
        {
          {
            solids.Append(solid);
            continue;
          }
        }
      }
      
      Autodesk.Revit.DB.GeometryInstance geomInst = geomObj as Autodesk.Revit.DB.GeometryInstance;
      if (null != geomInst)
      {
        
        refGeometry = geomInst.GetInstanceGeometry(geomInst.Transform);        
        GetSolids(refGeometry, ref solids,ref refGeometry);
      }
    }
  }
}


这里增加了refGeometry 来指向GetInstanceGeometry所返回的对象到主调用函数。保护了目标对象不释放。

作者:叶雄进文章来源:http://blog.csdn.net/joexiongjin/article/category/782739



作者: 慕容柔晴    时间: 2014-2-14 10:15
路过!!! 不发表意见……
作者: MIMDxFzL    时间: 2014-2-15 14:29
顶...... 楼下跟上.....
作者: 木鬼    时间: 2014-2-15 14:35
顶!!!!!!!!!!
作者: 孙雅    时间: 2014-2-15 14:38
顶!!!!!!!!!!
作者: 野风    时间: 2014-2-18 12:04
(*^__^*) 嘻嘻……
作者: 莞人莞事    时间: 2014-2-19 14:55
顶!!!!!!!!!!!!!!!!!!!!!!!!!
作者: levin    时间: 2014-2-20 14:04
顶起来…………




欢迎光临 EaBIM (https://eabim.net/) Powered by Discuz! X3.2