在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
1、问题描述最近在写C#下AE的开发,在循环获取数据并修改时碰到了两个问题“超出系统资源”和“超出打开游标最大数”;在网上看了一些资料,发现都是说在循环中没有释放已经使用过的对象,但是在循环中实际上是有为com对象赋值为null的,但是还是没法解决。后来想着将对象赋值为null和marshal是不是效果不一样,就特意写了一个简单的循环来测试,代码如下(初级代码,比较乱,请轻喷): 1 public void Test_释放游标方式() 2 { 3 string ssName = "controlpoint";//图层名称(里面有4w多条数据) 2、试验过程在测试中,专门打开一个控制点图层(里面有4w多条数据),然后根据条件循环建立游标获取对象; 情况一:在使用完游标之后,将其赋值为null;这时候对象实际上是没有被释放掉的,因此在283次循环时就会报错‘ora 超出打开游标最大数’; 情况二:在使用完游标时,在循环末尾,用marshal.releasecomobject方法来释放com对象,这时循环可以走完4w次;我认为这时对象是完全被释放掉了的。 同时在使用marshal.releasecomobject方法时,并没有增加多余的时间,循环执行时间上还是跟不释放对象一样(小数据量比较)。 3、结论在使用ArcEngine中的游标对象时,一定要在使用完之后进行对象的释放,否则会不定时出现上面的错误;而且需要使用marshal.releasecomobject方法来进行对象的释放,赋值为null是达不到目的的; 另外说一下“超出系统资源”的这个错误,这个在最初没有释放对象时,每次当数据量超过200就会不定时报这个错误,一直也没法解决;但是当我在循环中加上marshal.releasecomobject方法释放对象后,这个问题竟然莫名消失了(后来特意试了4000条数据,也可以通过测试)。相当于解决“超出打开游标最大数”的问题时,顺带着让另一个问题也消灭了(可能是我不理解其间的具体原理,有待深入)。 到这里,ArcEngine对象释放问题已经阐述完毕。以下是在解决过程中碰到的另一个问题,看官可以选择性忽略。 Other-补充问题(问题3:“COM对象与其基础RCW分开后就不能再使用”)如代码中黄色部分所示,在这里我碰到了一个很奇怪的问题,即在上面一句我已经用Marshal释放了pCur对象,但是后面仍然可以继续使用(指的是再次用Marshal释放)而不报错。在这里我是将pCur作为参数传递进方法内部,然后再次使用Marshal释放,我一共尝试了以下几种方式: ①普通的参数传递:可以正常使用,并Marshal而不报错; ②ref参数:也可以正常使用并Marshal而不报错 ③params参数:此时不能正常使用,在调用方法时就会报错“com对象与其基础rcw分开后不能再使用”,而且连方法内部都进不去。 经过一天的查找原因,我认为原因如下: 首先,params是数组型参数,我们一般是想达到分散传递任意个数的参数的目的;此时,我们看似传递的是一个个的参数,但是编译器在进入方法之前会做一项工作,即使用我们传递的这些分散的参数建立一个一维数组,然后将这个数组传递给方法进行后续的操作(注意:错误也就是在这一步出现,就是我们连方法都进不去就报错的原因)。 其次,因为C#中数组是引用类型,在建立数组时是同时进行堆和栈上的内存分配的,也即数组的实际内容是在堆上存储,而在栈上开辟一块内存用于保存数组名(即堆中保存实际数据的内存的地址)。这就是C#中引用类型变量建立的方式:引用类型的地址存放在栈上,而实际对象存储在堆上。 第三,ArcEngine的com对象建立就遵循上面的原则,及同时使用了堆和栈(这部分由.NET的rcw为我们做了,具体原理现在还不清楚);因此我们在C#实际使用ArcEngine的对象时就像普通的引用类对象一样。而当我们使用Marshal将建立的对象释放后(比如IFeatureCursor),相当于斩断了堆和栈之间的联系桥梁; 第四,而我们在Marshal过pCur对象一次之后,再像上面黄色代码的那一部分来调用pCur时,普通参数、ref参数都不会去寻找pCur所对应的在堆上的对象(形象一点就是都不会走这一段已经被斩断了的桥梁);但是params数组型参数不同,编译器在进入方法之前是需要进行一步数组建立的操作的,而在建立数组时是需要同时操作堆和栈的,这时候再去走那一段已经被斩断了的桥梁就无法通过,也就会报错“com与其基础rcw分开后不能再使用”。【这一步你也可以变换一种方式测试:即建立一个直接以数组作为参数的方法,然后使用时事先建立数组,再把数组作为参数传递。这时候你会发现,数组是无法建立成功的,报错就出现在这里】 结论:这里params数组参数的语法糖给我们了一个小坑,如果不去理解堆、栈的概念,还有方法的参数传递与使用,就会觉得这个错误报的莫名其妙;而当深入理解了C#中方法的参数类型、传递,以及引用类型对象的原理,就能理解这个错误。【以上只是我个人查找资料后的理解,总感觉理解了出错的原因,但是没法清楚的表达出来;还有关于最后堆、栈的问题,我理解的很浅,如果有不对的地方希望各位大神能指出来,我再修改】 |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论