技术开发 频道

.NET内存管理的非常好的实践

 【IT168技术文档】我们在实际编程中使用的内存往往都会超出程序需要的内存,对于桌面应用程序内存是相对廉价的,但如果你在开发ASP.NET应用程序,需要处理服务器上大量的内存时,过度使用内存可能会带来很多痛苦,因此有必要讨论一下.NET内存管理的非常好的实践,以减少内存浪费。

 程序员在为类中的成员变量获取内存时往往有些多余的行为,因为有些不必要的内存使用会浪费掉一些内存空间,我们来看一段代码:

  public class BadUse

 {

 private SqlConnection con = new SqlConnection();

 private DataSet ds = new DataSet("MyData");

 public BadUse() {}

 public BadUse(string connectionString)

 {

 SqlConnection = new SqlConnection(connectionString);

 }

 public BadUse(SqlConnection con)

 {

 this.con = con;

 }

 }

 如果在我们的系统中使用了多余的内存,类在被调用之前,甚至是构造函数被调用之前,就调用了对象成员初始化程序,它将为所有成员变量获取内存,在上面的代码中,在初始化期间我们创建了一个SqlConnection对象,在那之后,我们都调用默认的构造函数或创建对象的构造函数,因此没有使用已经创建好的对象,重新创建了一遍对象,因此浪费了内存空间。

 .NET内存管理非常好的实践方法:

public class GoodUse

 {

 private SqlConnection con = null;

 private DataSet ds = null;

 public SqlConnection Connection // Better to use Properties

 {

 get

 {

 if(this.con == null)   // Always check whether there is an existing object assigned to member

 this.con = new SqlConnection();

 return this.con;

 }

 set

 {

 if(value == null || this.con !=null)

 {

 this.con.dispose();     // Clears out Existing object if member is assigned to Null

 this.con = null;            //    Always better to assign null to member variables

 }

 if(value !=null) this.con = value;

 }

 }

 public GoodUse() {}

 public GoodUse(string connectionString)

 {

 this.Connection = new SqlConnection(connectionString); //Assignes new object to null member

 }

 public GoodUse(SqlConnection con)

 {

 this.con = con;

 }

 }

  从上面的代码我们就更清晰了,使用属性总比直接访问对象要好,这里还给了你一个接口方便以后修改每个调用,与此类似,使用事件访问程序访问事件总是非常好的的。

private MyDelegate MyEvent;

 public MyDelegate CheckEvent

 {

 add

 {

 MyEvent + =value;

 }

 remove

 {

 MyEvent -= value;

 }

 }

 在VB.NET中可以使用RaiseEvent,在代码中无论何时触发了事件都会调用它。

 使用Using和Try/Catch程序块

 使用可随意使用的对象时最好使用Using程序块,在.Net提供的所有构造函数中,Try /Catch和Using程序块经常调用Dispose()函数,只要对象实施了IDisposable,因此在.Net中使用Try /Catch和Using程序块总是非常好的的。来看下面的代码:

 public void Execute(string connectionstring, string sql)

 {

 SqlConnection con = new SqlConnection(connectionstring);

 SqlCommand cmd = new SqlCommand(sql, con);

 con.Open();

 cmd.ExecuteNonQuery();

 cmd.Dispose();

 con.Dispose();

 }

 在上面的代码片段中,我们简单地创建了SqlConnection和SqlCommand对象,这两个对象都实施了IDisposable,因此上面的代码可以按照非常好的实践方法重写如下:

 public void Execute(string connectionstring, string sql)

 {

 using(SqlConnection con = new SqlConnection(connectionstring))

 {

 using(SqlCommand cmd = new SqlCommand(sql, con))

 {

 con.Open();

 cmd.ExecuteNonQuery();

 }

 }

 }

 这样重写之后将会自动调用Dispose函数,我们不需要直接调用它,因此对于快速资源解除分配最好使用Using程序块。

 也可以使用Try/ Catch程序块,如:

 try

 {

 SqlConnection con = new SqlConnection(connectionstring);

 try

 {

 SqlCommand cmd = new SqlCommand(sql, con);

 con.Open();

 cmd.ExecuteNonQuery();

 }

 catch {}

 finally

 {

 cmd.Dispose();

 }

 }

 catch(){}

 finally

 {

 con.Dispose();

 }

 }

 接着是使用as或is比使用强制类型转换要好,也就是说如果我们想转换一个类型,应该使用as关键字而不是使用明确的类型映射。

object o = new SqlConnection();

 SqlConnection con = o as SqlConnection; // Better to use this

 SqlConnection con = CType(o, SqlConnection); // Not always better

  在上面的语句中,如果你使用第二个转换语句,如果CType不能转换成那个类型或在o中有空值,它将会抛出错误,但在使用了as的语句中不会抛出错误,而是使转换无效。

 调用函数时使用Structure

 调用函数时参数少是一件好事,如果直接向函数发送一个大对象将会花大量的时间发送多个参数,此时可以为那些要发送的参数创建一个Structure,然后直接发送这个Structure。

public void Callme(int x, int y, string zy)

 public void Callme(argumentStruct st) // Better in performance

  发送一个Structure总比发送离散对象要好。

 使用一个大型组件总比使用大量的小型组件要好,大型组件中有许多命名空间,而不是大量的小型类库,微软也是这么干的,它将所有的组件都创建在mscorlib.dll中了,减少了元数据的负荷、JIT编译时间和安全检查等。

 如果不是必须的最好避免使用线程。

 通常情况下,使用大量的线程可能导致性能下降,因为每个线程在独立运行时会消耗大量的内存,当你需要快速处理时可以使用线程,但它会增加内存消耗。

 当你创建线程时使用ThreadPool(线程池)。

 避免使用ArrayList和HashTables,当你需要插入随机数据时可以使用链接数组。

 如果你看到ArrayList或HashTables的内部结构,就知道它仅仅是数组的打包,无论何时向这些结构中插入对象时,它将为所有已分配量重新声明,然后手动转变它们,ArrayList是一个对象数组,HashTable是一个结构数组。

 另一个奇怪的事情是,ArrayList或HashTables的区间系数是4,这意味着它无论何时需要内存时分配的内存总是4的倍数,当你需要随机插入时,LinkLists、Generic Lists和LinkedArrays比Collections对象的性能要好,当你需要添加数据和按顺序显示数据时使用Collections更好。

0
相关文章