EaBIM一直以来积极响应国家“十二五”推进建筑业信息化的号召,对建筑领域的信息技术开展深入技术交流和探讨!致力于打造“BIM-建筑师-生态技术”三位一体综合资源交流共享平台,希望为BIM与可持续设计理念及技术的普及做出微小的贡献!!!

EaBIM

 找回密码
 注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

搜索
查看: 728|回复: 7
打印 上一主题 下一主题

访问实体的几何数据时,抛出 SEHException错误(只有Release版出现)

[复制链接]

1514

主题

7465

帖子

1万

积分

admin

Rank: 10Rank: 10Rank: 10Rank: 10Rank: 10Rank: 10Rank: 10Rank: 10Rank: 10Rank: 10

积分
12396

社区QQ达人

跳转到指定楼层
楼主
发表于 2014-1-15 14:15:13 | 只看该作者 回帖奖励 |正序浏览 |阅读模式

上周处理了一个有趣的问题,与垃圾回收机制有关。当获取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


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
收藏收藏 转播转播 分享分享 分享淘帖 支持支持 反对反对
工作时间:工作日的9:00-12:00/13:30-18:00,节假日不在线,请勿留言

5

主题

874

帖子

1406

积分

BIM经理

Rank: 6Rank: 6Rank: 6Rank: 6Rank: 6Rank: 6

积分
1406
6F
发表于 2014-2-18 12:04:23 | 只看该作者
(*^__^*) 嘻嘻……

5

主题

726

帖子

1692

积分

BIM经理

Rank: 6Rank: 6Rank: 6Rank: 6Rank: 6Rank: 6

积分
1692
3F
发表于 2014-2-15 14:29:55 | 只看该作者
顶...... 楼下跟上.....

11

主题

869

帖子

1482

积分

BIM经理

Rank: 6Rank: 6Rank: 6Rank: 6Rank: 6Rank: 6

积分
1482
2F
发表于 2014-2-14 10:15:31 | 只看该作者
路过!!! 不发表意见……
*滑块验证:
您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|EaBIM网 ( 苏ICP备2020058923号-1  苏公网安备32011502011255号

GMT+8, 2024-9-29 14:22

Powered by Discuz! X3.2 Licensed

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表