c#

位置:IT落伍者 >> c# >> 浏览文章

引以为戒 .NET开发者常犯的错误


发布日期:2018年08月18日
 
引以为戒 .NET开发者常犯的错误

NET开发过程中不是程式的无法运行就是程式的效率慢的同蜗牛在爬; 这种情况在NET的新手中尤其常见我不知道为什么一些介绍NET开发的书本里引用的例子代码也对此问题视而不见尤其让我郁闷的是一些我喜欢的书也出现了同样的问题

这篇文章不仅对NET开发者的新手有帮助同样对哪些有经验也带来一些启示和参考

他们会遇到什么样的问题?

数据库连接超时

创建的对象只管用不管释放

调试(Debug)模式下编译后就用于应用环境中了

实际作业模式分享

上面的问题就像毒瘤积累到一定程度就爆发且影响深远

数据库连接超时篇

若要知道数据库连接超时问题先看下面一段代码:

[sample]

Public Shared Function getOEMPN(ByVal psPN As String ByRef OEMPN As String) As BSResult

Dim clsResult As New BSResult

Try

clsResultResultID =

Dim dtResult As New DataTable

Dim Sql As String = StringEmpty

Dim clsOraDb As New clsOraClienDb

Dim strConn As String = ConfigurationManagerConnectionStrings(ConnectionString)ConnectionString

clsOraDbOpen(strConn)这里Open后后面看不到 clsOraDbClose

Sql = SELECTSATBMMBRNDOEMPN FRUNO FROM SATBMMBRNDWHERE SATBMMBRNDMATNO = :MATNO

Dim params() As racleParameter = {New OracleParameter(MATNO psPN)}

If clsOraDbFillDataTable(Sql dtResult params) = False Then

Return clsResult

End If

If dtResult Is Nothing Then

Return clsResult

End If

If dtResultRowsCount > Then

OEMPN = dtResultRows()(FRUNO)ToString()

Else

OEMPN =

End If

clsResultResultID =

Return clsResult

Catch ex As Exception

clsResultResultID =

Return clsResult

End Try

End Function

对上述代码行的部分解释

Dim clsOraDb As New clsOraClienDb:引用数据库连接的类;

clsOraDbOpen(strConn):打开数据库连接;

然后整个函数你再找不到关闭数据库连接的动作是要等着操作系统来释放吗? 有人就说啦看起来好像没有什么大不了的这仅仅是一个函数而已;数据库打开连接未关闭不会影响到整个应用程式;果真是这样吗?

让我们谈谈数据库连接的问题在Oracle数据库里一般默认的数据库连接数最多也就多来个不会超过即使你改变这个连接数但无论怎样它的连接数是有限的不可能无限地供你消耗

在Web这个程式里它不仅不会自动关闭数据库连接象这样的函数还会每次调用都会重新用掉一个数据库连接;如果象这样的函数很多的话你就等着一个错误警告页面弹出来如Database Connection Timeout…等讯息

这还不算什么更有甚者尽然在循环语句里写下面的代码如

[sample]

Foreach(DataRow row in tablselect(ProductID)

……………

clsOraDbOpen(strConn)

…………

Next

有人还喜欢玩下面的语句:

[sample]

Foreach(DataRow row in tablselect(ProductID)

Foreach(DataColumn col in lumns)

……………

clsOraDbOpen(strConn)

Next

…………

Next

说到这有人就问啦我在开发环境下测试一点问题都没有呀?是呀你是没有问题我想问的是你开发环境的测试数据有几笔?

现在问题已经知道在哪里怎么解决?

针对[sample]做如下处理注意下面代码:

Public Shared Function getOEMPN(ByVal psPN As String ByRef OEMPN As String) As BSResult

Dim clsResult As New BSResult

Try

clsResultResultID =

Dim dtResult As New DataTable

Dim Sql As String = StringEmpty

Dim clsOraDb As New clsOraClienDb

Dim strConn As String =

ConfigurationManagerConnectionStrings(ConnectionString)ConnectionString

clsOraDbOpen(strConn)注释这里Open后后面看不到 clsOraDbClose

Sql = SELECTSATBMMBRNDOEMPN FRUNO FROM SATBMMBRNDWHERE SATBMMBRNDMATNO = :MATNO

Dim params() As racleParameter = {New OracleParameter(MATNO psPN)}

If clsOraDbFillDataTable(Sql dtResult params) = False Then

Return clsResult

End If

If dtResult Is Nothing Then

Return clsResult

End If

If dtResultRowsCount > Then

OEMPN = dtResultRows()(FRUNO)ToString()

Else

OEMPN =

End If

clsResultResultID =

clsOraDbClose注释后面看到 clsOraDbClose

Return clsResult

Catch ex As Exception

clsOraDbClose 注释程序异常也看到 clsOraDbClose

clsResultResultID =

Return clsResult

Throw ex

End Try

End Function

注意上面的两句代码:clsOraDbClose和clsOraDbClose;

在异常处理的时候特别提醒两点

)你的数据库关闭的时候应该是在代码行而不是后;

)有人不习惯(或者一时疏忽)加上行的代码;

针对[Sample]和[sample]把打开数据库连接写在所有的循环语句之前如:

clsOraDbOpen(strConn)

Foreach(DataRow row in tablselect(ProductID)

……………

…………

Next

当然还有另外一个做法就是用Using语句提交NET应用的垃圾收集器自动收集;相关的文章很多这里不再特别赘述

对象只管创建应用不管释放篇

我们继续用[Sample]的代码:

Dim dtResult As New DataTable

谁会发现它被释放你不能我也不能从来没有被释放过

Dim dtResult As New DataTable行的代码解释是要在内存划分一个空间给这个定义的对象dtresult;系统要划分多大的空间呢?呀我没有研究过(留给那些有心人吧呵呵)但有一点要在内存划分一个空间就是要占用内存那么内存有多大呢不是无限大吧也是有限的所有运行上述代码的最终结果是系统的执行效率越来越慢有人就怀疑我有内存G的加上虚拟内存就更大我只能说你的怀疑没错;可是你的应用程序就用这么一只函数吗?我想肯定不是所以上百只函数的应用执行对内存的消耗可想而知如果是后台自动运行的程序及时是一个function也会让系统崩溃这只是一个简单的例子有更复杂的;象这样的对象应用还有:Dataset DatatableDataReaderDataAdapterDatagrid等;

那么怎么解决这些问题呢?

)在Try catch 语句前定义好所用的对象; 如:

Dim dtResult As New DataTable

Dim DR as New DataReader

Dim DS as New Dataset

Try

Catch ex As Exception

Throw ex

Finally

End Try

)释放的语句如下:

Dim dtResult As New DataTable

Dim DR as New DataReader

Dim DS as New Dataset

Try

……………

Catch ex As Exception

释放应用的对象

Throw ex

Finally

使用完后释放应用的对象

dtResultdispose从内存里清楚该对象

DRdispose从内存里清楚该对象

DSdispose从内存里清楚该对象

End Try

有人习惯写成下面这样:

Dim dtResult As New DataTable

Dim DR as New DataReader

Dim DS as New Dataset

Try

使用完后释放应用的对象

dtResultdispose从内存里清楚该对象

DRdispose从内存里清楚该对象

DSdispose从内存里清楚该对象

Catch ex As Exception

释放应用的对象

Throw ex

Finally

End Try

这不是也释放了吗?我想问的是如果程序出现异常它们会释放吗?我肯定得告诉大家

它们一定不能释放为了确保程序的稳定运行我建议大家都来用Try Catch语句

)绝不建议在循环语句写如下的语句

Foreach (DataRow row in tablselect(ProductID)

……………

Dim DS new Dataset 记住此乃写代码之大忌;

Dim DT new Databable…

…………

Next

还有一种写法

Dim DS new Dataset

Dim DT new Databable…

Foreach (DataRow row in tablselect(ProductID)

DS=GetDatase

DT=GetDatatable……………

…………

Next

正确的写法是

Dim DS new Dataset

Dim DT new Databable…

Try

Foreach (DataRow row in tablselect(ProductID)

DS=nothing每次使用都先把内存空间释放出来

DT=nothing每次使用都先把内存空间释放出来

DS=GetDatase

DT=GetDatatable……………

…………

Next

Catch ex As Exception

Throw ex

Finally

DSdispose

DTdispose

End Try

另外提醒大家一点记得用 For Each 语句替代For i= to Rowcount这样的效率改善也是明显的;

调试(Debug)模式下编译就用于应用环境中篇

大家看下面的图片

)thisstylewidth=; border=>

有人会留意这个界面吗?有但一定不多

接着程式开发好(也包括单元测试)然后编译直接分发到应用环境

整个过程就结束了谁也不曾想这里埋下了一个深深的地雷;据微软的人讲这样分发的程式到应用环境你有多少内存恐怕都不够所以微软建议我们做如下的工作:

请将nfig中的debug及Trace均设为False还有您的所有程式请确保compile为Release Mode

Application set up for debugging

One reason for high memory that we see here in Support a lot is when you have debugging tracing or both enabled for your application

While you are developing your application this is a necessityBy default when you create your application in Visual Studio NET you will see the following attribute set in your nfig file:

true />

and/or

true />

Also when you do a final build of your application make sure that you do this in Release mode not Debug mode

如果不这样做会有什么事情发生? 我分享一个同事的感受给大家已经是很强悍的的DB和AP服务器(全部是刀片式服务器)了可是问题一而再再而三地发生那种感觉真的很无助很凄凉啊~

后来的结果发现是内存使用率超高到一定限度的时候就会反应变慢这个时候只要重启IIS就可以好一段时间;后来分析IIS用到实体加虚拟的内存超过G就会爆掉;

这就是原因你想遇到吗?那就不妨试试

实际操作分享篇

上面三个环节任何一个发生问题都会影响到系统的效率我分享我们实际的作业的过程发生的一些情况及怎么解决这些问题

)内存使用达到峰值导致程序无法继续运行;

有个同事分享了他们的经验如下(原话分享)

我们有一些程式是server跑的Job并有越来越多之势而大家在写程式的时候可能比较少考虑到耗内存这个问题

下面的例子也许会给我们一点启示

image id=img  alt= src=http://imgeducitycn/img_///jpg onload=javascript:if(thiswidth>)thisstylewidth=; border=>

下面也是原话:

Pls help to check the Run In Rack Job program It will no response after running two or three days the AP server Memory usage will over G after we close the the program Memory will decrease to

大致意思是在服务器端(也叫后台)自动跑的一只程式运行了两三天后停止运行了

检查Server的内存使用率时发现超过了G;在关掉了这只程式后它就降到了G…下面的图片为证

image id=img alt= src=http://imgeducitycn/img_///jpg onload=javascript:if(thiswidth>)thisstylewidth=; border=>

)进程请求过多导致CPU无法及时处理程序效率反应较慢

下面都是同事的原话:

年后产量逐渐增加新的问题又出现了从Server Performance上分析和上次Memory过高不同的是CPU使用率过高每当CPU过高的时候产线会大面积的反应说慢(这点和连接到哪台AP有关系)每次慢的时候我们就找到CPU过高的那台APrecycle IIS的application pool后就OK了于是我么再次找到Bon帮忙分析(结论:微软结案报告 V SRT Web service cant serve IISReset can fixmsg)并给出了开发程序时的一些建议

结论大致是说没有进程占用了特别高的CPU也没有进程占用CPU时间过长只是对DB的请求的进程过多(比较吻合厂的实际状况—附件多刷的快)加起来就整体过高还发现了很多DLL是built in debug mode这些DLL占用了过多的memory资源后来根据Bon的建议我们修改了IIS application pool的设定如下解决过多请求不能及时处理而造成CPU过高的问题

image id=img alt= src=http://imgeducitycn/img_///jpg onload=javascript:if(thiswidth>)thisstylewidth=; border=>

这里有一些问答关于应用连接池(Application Pool)的设定对理解这样的设置有一定的帮助:

Is one application pools maximum memory usage G?

A&: Each application pool is a wwpexe wwpexe is a process Every process has G User mode virtual address so the maximum memory usage for application pool is G However you cant make sure that there is no memory fragment issue Therefore Out of memory always occur after G according to our experience

Is each application pool independent on memory usage?

A&: Different application pools are different wwpexe so each application pools maximum memory usage is G

Can setup maximum CPU usage on each application pool?

A&: You can monitor it but you cant setup it

               

上一篇:.net中的mapinfo开发:准备

下一篇:c#如何获得cpu,硬盘的物理序列号