转贴: 在使用SPSite对象时容易发生内存泄漏!造成内存泄漏的原因是没有正确地关闭SPSite对象
2009-03-18 15:06
573 查看
如题所说,在使用SPSite对象时容易发生内存泄漏!造成内存泄漏的原因是没有正确地关闭SPSite对象,请大家Review一下代码,及时修正!
项目中,对系统进行压力测试时,出现了大量的异常信息,类似如下面的:
Microsoft.SharePoint.SPException: Attempted to make calls on more than one thread in single threaded mode. (Exception from HRESULT: 0x80010102 (RPC_E_ATTEMPTED_MULTITHREAD)) ---> System.Runtime.InteropServices.COMException (0x80010102): Attempted to make calls on more than one thread in single threaded mode. (Exception from HRESULT: 0x80010102 (RPC_E_ATTEMPTED_MULTITHREAD))
at Microsoft.SharePoint.Library.SPRequestInternalClass.SetVar(String bstrUrl, String bstrName, String bstrValue)
at Microsoft.SharePoint.Library.SPRequest.SetVar(String bstrUrl, String bstrName, String bstrValue)
--- End of inner exception stack trace ---
at Microsoft.SharePoint.Library.SPRequest.SetVar(String bstrUrl, String bstrName, String bstrValue)
at Microsoft.SharePoint.SPListItemCollection.EnsureListItemsData()
at Microsoft.SharePoint.SPListItemCollection.Undirty()
at Microsoft.SharePoint.SPBaseCollection.System.Collections.IEnumerable.GetEnumerator()
at OA2.MossAccessBlock.Portal.NewsHelper.GetAreaNewsDom(String subType, String area, Int32 pictureNum, Int32 newsNum) in D:\OA2_BuildVersion\MossAccessBlock\Portal\NewsHelper.cs:line 191
上面的异常的意思是说:在单线程模式下尝试进行多线程呼叫。在压力测试的过程中,出现了诸如“服务器内存不足”、“连接不到数据库服务器”、“找不到网站”等一些在单用户(用户访问量较小的情况下)使用的时候不会出现的异常,而在这些异常出现后的一段时间内,服务器会给出HTTP500的响应(MOSS服务器挂了),幸运的话过一段时间等压力降下来后服务器会自动地活过来,这现象比较神奇;倒霉的话应用程序池会自动停止,但我们一般都是RESET IIS就了事了,就是因为这样,如果没有做大量的压力测试,不容易给人发现。
经过大量的异常信息对比,我们发现异常中的代码都会与创建SPSite对象时相关联的,经过翻查SDK,有这样一段话:
If you create your own SPSite object, you can use the Dispose method or the Close method to close the object. However, if you have a reference to a shared resource, such as when the object is provided by the SPControl.GetContextSite method in a Web Part, do not use either method to close the object. In scenarios where you have a reference to a shared resource, instead let Windows SharePoint Services or your portal application manage the object. Using either method on a shared resource causes an access violation error to occur.
我们在使用SPSite的时候有两种途径能获得该对象:1. New SPSite(siteURL); 2. SPControl.GetContextSite(this.Context)
SDK的意思是说我们在使用第一种方法获得SPSite时,可以(应该说是必须)使用Close()方法或Dispose()方法关闭该对象;而使用GetContextSite()获得的SPSite对象一定不能使用那两个方法关闭该对象,使用GetContextSite()等类似的方法,如从Current对象出获得的SPSite对象,都不能进行了关闭操作,因为那是一个共享的对象,如强行关闭的话程序会出错(验证过的确会出错,当初所有代码的SPSite都没有关闭就是因为在关闭时会导致程序出错,所以没有关闭,但并没注意是用哪种方法获得的SPSite)。
很明显,共享的对象在理论一是性能是优于独立创建的一个新的对象,起码就会少创建对象的时间等操作,所以在只有一个网站集的系统(像巴陵石化项目)中,请尽量使用GetContextSite()方法获得网站集对象SPSite,以减少出错的机会及优化程序的性能。
而SPSite.Close()和SPSite.Dispose()有什么不同呢?以前看过.Net的书,Close()仅仅是释放当前对象的资源,而Dispose()在释放当前对象资源时还会调用其成员对象的Dispose()方法,以释放成员对象的资源,所以Dispose()比Close()释放得更彻底,在找这个线程异常的原因时,我也分别对Close()方法和Dispose()方法做了压力测试,使用Close()方法后,抛出线程异常的数量比没有使用任何方法时明显减少了,但还是会有;使用Dispose()方法后,就再也没有抛出该异常。我想原因是SPSite对象内有个SPWebCollections对象,包含了网站集下所有的子站点对象SPWeb,SPWeb和SPSite一样,在SDK里均有如SPSite一样的说明,所以使用SPSite.Close()方法还是不够彻底,除非你自己手工去Dispose所有的SPWeb对象。
综上所述,在使用New方法独立创建一个SPSite对象时,得写成类似下面形式:
using (SPSite site = new SPSite(siteURL or siteGUID))
{
// your code here
}
或
SPSite site = null;
try
{
site = new SPSite(siteURL or siteGUID);
// your code here
}
catch{}
finially
{
site.Dispose();
}
最后说说有关MOSS里的特权代码,就是以系统帐号身份运行某一程序段,看下面代码:
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite site = new SPSite(web.Site.ID))
{
// do things assuming the permission of the "system account"
}
});
在使用特权代码时,必须注意在特权代码中的SPSite和SPWeb 对象必须是独立创建的对象,不能使用共享对象,否则也会抛异常,就是说不能写成像下面的代码:
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite site = SPControl.GetContextSite(this.Context))
{
// do things assuming the permission of the "system account"
}
});
项目中,对系统进行压力测试时,出现了大量的异常信息,类似如下面的:
Microsoft.SharePoint.SPException: Attempted to make calls on more than one thread in single threaded mode. (Exception from HRESULT: 0x80010102 (RPC_E_ATTEMPTED_MULTITHREAD)) ---> System.Runtime.InteropServices.COMException (0x80010102): Attempted to make calls on more than one thread in single threaded mode. (Exception from HRESULT: 0x80010102 (RPC_E_ATTEMPTED_MULTITHREAD))
at Microsoft.SharePoint.Library.SPRequestInternalClass.SetVar(String bstrUrl, String bstrName, String bstrValue)
at Microsoft.SharePoint.Library.SPRequest.SetVar(String bstrUrl, String bstrName, String bstrValue)
--- End of inner exception stack trace ---
at Microsoft.SharePoint.Library.SPRequest.SetVar(String bstrUrl, String bstrName, String bstrValue)
at Microsoft.SharePoint.SPListItemCollection.EnsureListItemsData()
at Microsoft.SharePoint.SPListItemCollection.Undirty()
at Microsoft.SharePoint.SPBaseCollection.System.Collections.IEnumerable.GetEnumerator()
at OA2.MossAccessBlock.Portal.NewsHelper.GetAreaNewsDom(String subType, String area, Int32 pictureNum, Int32 newsNum) in D:\OA2_BuildVersion\MossAccessBlock\Portal\NewsHelper.cs:line 191
上面的异常的意思是说:在单线程模式下尝试进行多线程呼叫。在压力测试的过程中,出现了诸如“服务器内存不足”、“连接不到数据库服务器”、“找不到网站”等一些在单用户(用户访问量较小的情况下)使用的时候不会出现的异常,而在这些异常出现后的一段时间内,服务器会给出HTTP500的响应(MOSS服务器挂了),幸运的话过一段时间等压力降下来后服务器会自动地活过来,这现象比较神奇;倒霉的话应用程序池会自动停止,但我们一般都是RESET IIS就了事了,就是因为这样,如果没有做大量的压力测试,不容易给人发现。
经过大量的异常信息对比,我们发现异常中的代码都会与创建SPSite对象时相关联的,经过翻查SDK,有这样一段话:
If you create your own SPSite object, you can use the Dispose method or the Close method to close the object. However, if you have a reference to a shared resource, such as when the object is provided by the SPControl.GetContextSite method in a Web Part, do not use either method to close the object. In scenarios where you have a reference to a shared resource, instead let Windows SharePoint Services or your portal application manage the object. Using either method on a shared resource causes an access violation error to occur.
我们在使用SPSite的时候有两种途径能获得该对象:1. New SPSite(siteURL); 2. SPControl.GetContextSite(this.Context)
SDK的意思是说我们在使用第一种方法获得SPSite时,可以(应该说是必须)使用Close()方法或Dispose()方法关闭该对象;而使用GetContextSite()获得的SPSite对象一定不能使用那两个方法关闭该对象,使用GetContextSite()等类似的方法,如从Current对象出获得的SPSite对象,都不能进行了关闭操作,因为那是一个共享的对象,如强行关闭的话程序会出错(验证过的确会出错,当初所有代码的SPSite都没有关闭就是因为在关闭时会导致程序出错,所以没有关闭,但并没注意是用哪种方法获得的SPSite)。
很明显,共享的对象在理论一是性能是优于独立创建的一个新的对象,起码就会少创建对象的时间等操作,所以在只有一个网站集的系统(像巴陵石化项目)中,请尽量使用GetContextSite()方法获得网站集对象SPSite,以减少出错的机会及优化程序的性能。
而SPSite.Close()和SPSite.Dispose()有什么不同呢?以前看过.Net的书,Close()仅仅是释放当前对象的资源,而Dispose()在释放当前对象资源时还会调用其成员对象的Dispose()方法,以释放成员对象的资源,所以Dispose()比Close()释放得更彻底,在找这个线程异常的原因时,我也分别对Close()方法和Dispose()方法做了压力测试,使用Close()方法后,抛出线程异常的数量比没有使用任何方法时明显减少了,但还是会有;使用Dispose()方法后,就再也没有抛出该异常。我想原因是SPSite对象内有个SPWebCollections对象,包含了网站集下所有的子站点对象SPWeb,SPWeb和SPSite一样,在SDK里均有如SPSite一样的说明,所以使用SPSite.Close()方法还是不够彻底,除非你自己手工去Dispose所有的SPWeb对象。
综上所述,在使用New方法独立创建一个SPSite对象时,得写成类似下面形式:
using (SPSite site = new SPSite(siteURL or siteGUID))
{
// your code here
}
或
SPSite site = null;
try
{
site = new SPSite(siteURL or siteGUID);
// your code here
}
catch{}
finially
{
site.Dispose();
}
最后说说有关MOSS里的特权代码,就是以系统帐号身份运行某一程序段,看下面代码:
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite site = new SPSite(web.Site.ID))
{
// do things assuming the permission of the "system account"
}
});
在使用特权代码时,必须注意在特权代码中的SPSite和SPWeb 对象必须是独立创建的对象,不能使用共享对象,否则也会抛异常,就是说不能写成像下面的代码:
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite site = SPControl.GetContextSite(this.Context))
{
// do things assuming the permission of the "system account"
}
});
相关文章推荐
- 在使用SPSite对象时容易发生内存泄漏
- 【PHP内存泄漏案例】PHP对象递归引用造成内存泄漏
- 使用MyEclipse中用Hibernate反向工程生成的DAO会发生对象无法存储到数据库的现象,原因是没有运用事务。
- 深度分析内存泄漏原因,使用MAT工具检测内存泄露和性能
- Android中使用Handler造成内存泄露的原因和解决方法
- 使用 Android Studio 检测内存泄漏与解决内存泄漏问题
- NSTimer保留目标对象引起循环引用造成内存泄漏解决办法
- 资源未关闭造成的内存泄漏
- JAVA内存泄漏原因和内存泄漏检测工具
- 程序崩溃80%的原因还是因为对象没有实例化就使用
- 使用 Android Studio 检测内存泄漏与解决内存泄漏问题
- 使用proxool连接池 ,连接没有关闭的原因
- 利用运行时,给UIImageView写一个分类,交换里面的setImage的方法,可以重绘图片,提高内存的利用率(要是没有重绘图片,直接使用系统提供的setImag就会造成占用大量的内存问题)
- 在web项目中使用 ThreadLocal 要谨慎,使用不当容易造成内存溢出
- 接收对 http://192.168.1.18:8001/ObtainData/Service 的 HTTP 响应时发生错误。这可能是由于服务终结点绑定未使用 HTTP 协议造成的。这还可能是由于服务器中止了 HTTP 请求上下文(可能由于服务关闭)所致。
- JAVA内存泄漏原因和内存泄漏检测工具
- Android中MVP模式的使用及内存泄漏原因分析(一)
- android开发中单例造成的内存泄漏原因及解决方案
- JAVA内存泄漏--内存泄漏原因和内存泄漏检测工具(zt)
- js闭包避免内存泄漏 减少内存使用 避免对象无法回收注意事项