访问实体的几何数据时,抛出 SEHException错误(只有Release版出现)
2011-02-21 13:55
288 查看
上周处理了一个有趣的问题,与垃圾回收机制有关。当获取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所返回的对象到主调用函数。保护了目标对象不释放。
--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所返回的对象到主调用函数。保护了目标对象不释放。
相关文章推荐
- Android模拟器访问google网站获取天气信息时,出现 java.net.UnknownHostException: www.google.com 错误
- Windows2000 在保存IP安全数据时出现拒绝访问错误80070005的解决方法
- 关于自定义实体集合绑定datagrid控件在进行编辑时出现错误"向原始数据存储区提交行时出错"的原因.
- C# 模拟post数据提交时 出现如下错误: System.Net.WebException: 远程服务器返回错误: (417) Expectation Failed 的解决办法
- C# post数据时 出现如下错误: System.Net.WebException: 操作超时
- [转]C# post数据时 出现如下错误: System.Net.WebException: 远程服务器返回错误: (417) Expectation Failed 的解决办法
- C# post数据时 出现如下错误: System.Net.WebException: 操作超时
- Oracle12c 通过IP访问数据出现ORA-12505错误
- C# post数据时 出现如下错误: System.Net.WebException: 远程服务器返回错误: (417) Expectation Failed 的解决办法
- Restful数据访问出现HTTP 400错误 解决
- Android 3.0 访问donet webService 出现 android.os.NetworkOnMainThreadException错误!
- C# post数据时 出现如下错误: System.Net.WebException: 操作超时
- SSH框架问题——hbm.xml配置出现的org.hibernate.MappingException: Could not determine type for:(貌似叫数据类型转换错误)问题
- C# post数据时 出现如下错误: System.Net.WebException: 远程服务器返回错误: (417) Expectation Failed 的解决办法
- C# post数据时 出现如下错误: System.Net.WebException: 远程服务器返回错误: (417) Expectation Failed 的解决办法
- Asp.Net : 捕捉和记录网站中出现的所有未处理错误,抛出详细的页面来源和访问ip,调用的接口方法及异常实例(记事本日志,系统日志及数据库日志)
- System.Data.SqlClient.SqlException: 在与 SQL Server 建立连接时出现与网络相关的或特定于实例的错误。未找到或无法访问服务器。请验证实例名称是否正确并且 SQL Server 已配置为允许远程连接。 (provider: SQL Network Interfaces, error: 26 - 定位指定的服务器/实例时出错)
- MVC 在提交一个表单数据时出现System.Web.HttpRequestValidationException (0x80004005):错误
- Android5.0以上使用XUtils访问网络出现错误或者网络数据无法加载: java.io.IOException: stack size 1036KB
- 删除datatable的行后,出现“不能通过已删除的行访问该行的信息”的错误,即DeletedRowInaccessibleException