asp内存和速度优化,第一部分(英文版)

发表于:2007-06-30来源:作者:点击数: 标签:
Memory and Speed Optimization with ASP - Part I It is an all to familiar problem: optimizing the memory and speed of your web sites. Maybe you have been, more than once a week, in the situation where your web server stopped giving you any A
Memory and Speed Optimization with ASP - Part I
It is an all to familiar problem: optimizing the memory and speed of your web sites. Maybe you have been, more than once a week, in the situation where your web server stopped giving you any ASP page, while the HTML pages were correctly displayed. One of the challenges faced by the web developers is how to create a fast (usually a faster that the one you have) application out of a series of HTML and ASP pages.

When programming ASP pages, memory and speed optimization can be acquired in two different ways. Because HTML pages are not processed at the server-side, we will talk more about memory and speed optimization of ASP pages:

By programming good ASP pages. This article is all about optimizing by writing good ASP pages.
By configuring the web server. We will cover this topic in another article.
When talking about optimizing ASP pages, we should start from the deepest level: basic variables.

One of the biggest differences between Visual Basic (VB) and ASP programming is the variable declaration. VB is a programming language, so you can define variables of a specific type:

Dim I as Integer        ‘’ Integer Declaration
Dim a$             ‘’ String declaration
Dim objMyCom as Object     ‘’ Object Declaration
Dim var as Variant         ‘’ Variant declaration

While ASP is a scripting language, where the only available type is VARIANT type. All the variables declared in ASP are of type VARIANT . Unfortunately, this makes all the operations slower, because the work with VARIANT is slower. The system has to first evaluate the type of the variant, convert it to the most appropriate of the operation that is to be done, and then make the operation.

VARIANT is a very smart type of variable. It has great capabilities of storing EMPTY and NULL values, along with any types of data, such as (integers, doubles, strings, currency and dates, arrays or objects).

Optimizing memory and speed when working with ARRAYS.
ASP programmers are usually not very good friends with ARRAYS. Using ARRAYS is more common to VB programmers that use them to store data. As little as you use arrays, you should have in mind the following way of optimizing array aclearcase/" target="_blank" >ccess:

Arrays are made from continuous blocks of memory. Reading and writing an item of an array is slower than accessing a simple variable. For each access to an item in an array, the runtime environment has to determine the position of the item in the memory, based on the first element of the array and the index. Therefore, it‘’s faster to read/write a variable, than an array item. Therefore, if you need to use the same array item in a loop repeatedly, you‘’d better assign the item to a variable and use that variable instead.

E.g. :

<%
‘’ this will calculate for each element, the value a(i) = 2i ( = 2 * 2 * 2 - for i times)
Dim a(20)     ‘’ The array
Dim i,j    ‘’ indexes
Dim tempVar     ‘’ a temporary variable
‘’ Non-optimized Array Access:
For i = lBound(a) to uBound(a)
     a(i) = 1
     For j = 2 to i
     a(i) = a(i) * 2
     next j
Next
‘’ Optimized Array Access
For i = lBound(a) to uBound(a)
     tempVar = 1
     For j = 2 to i
     tempVar = tempVar * 2
     next j
a(i) = tempVar
Next
%>

Because of the way of calculating the position of an element in memory, access to items in bidimensional arrays is very slow when compared to accessing items in single dimensional arrays. Think about this when designing your algorithms.

A good way of optimizing speed of multidimensional arrays is to reduce them to a single dimensional array. Instead of using a 10 by 10 matrix, try to use a 100-element array to speed up access. In this case, you have to manually find your items in the array. If you use i and j as indices, and you used to access an element like A(i, j), the new way of accessing the items will be A((i*10)+ j), where i and j are the original indices.

In ASP there are few ways of declaring arrays. The difference between the declaration method is the way in which ASP allocates and uses memory.

1. Dim A (10) ‘’ declaration of static array with 10 elements


Access to its items is the fastest, and uses less memory. Unfortunately, it can not be resized.


2. Dim A ( ) ‘’ declaration of dynamic array, with unspecified number of elements
Redim A(10) ‘’ Dimensioning the array to the requred size


After the declaration, before its first usage, the array has to be dimensioned using Redim A(nr of items). By using this declaration, you avoid problems of dimensioning the array, but you slow down the access to the array‘’s items by 50 -60%!


3. Dim A ‘’ declaration of a Variant variable
Redim A(1000) ‘’ assignment of an array to the variant

Declaration of a variable, which has an array assigned to it. The access to its items is 50% slower than for case 2, and about 75-80% slower than the first declaration.


4. Dim A ‘’ declaration of a Variant variable
A = Array( 1, 2.0 , "three" ) ‘’ assignment of an array created, when we know their number and values

This declaration mode seems to be as fast the first one, because of the function call "Array". Unfortunately this way of declaration is not very handy, because you have to have access to all the Array’s items from the declaration point.
Another problem that appears when using arrays is of re-dimensioning the arrays by using:

Redim a(200) ‘’ re-dimensioning the array to another size

Or by using:

Redim Preserve a(200)    ‘’ re-dimensioning the array to another size, and
‘’ preserving it‘’s current values

When re-dimensioning arrays, the runtime environment has to create a block of memory of the new required size, copy the old values of the array to the new array (if you are using Redim), and eventually cropping the array (if the new size is smaller than the original). Re-dimensioning arrays creates a big overload for the server, especially if you are also preserving its items. The only way of optimizing this is to try not to use it. Try to dimension your arrays from the declaration, and try as seldom as possible to re-dimension them.

Optimizing memory and speed when working with Objects.
Maybe the most useful optimization is achieved when object access is optimized. We use objects in almost all ASP pages, starting with database access objects, and finishing with custom-made objects. Everybody knows that programmers are inherently lazy. This fact can usually get us into trouble. From ASP, you have access to different objects, but the most used ones are the ones for database access (mostly ADO, or DAO) or MTS objects.

The way you create the object is important because it can speed up, or slow down your ASP page. If you want to create objects that reside in the MTS environment, the best way to create the object is by using the Server.CreateObject("ProgramID") .

E.g. :

Set myClass = Server.CreateObject("MyMtsComponent.MyTestClass")

The Server.CreateObject function call invokes the MTS to create the object and handle it. If the object is not installed in the MTS environment, you will only create processor and memory over head by passing it through Server.CreateObject.

On the other hand, CreateObject is more useful when creating objects that are not MTS objects, like database access objects, or ActiveX controls that are not installed in the MTS environment.

E.g. :

Dim myMTSObject
myMtsObject  = Server.CreateObject ( "myMTSComponent.myClass" )

Creating an MTS object by using the Server.CreateObject function call will create the object in the MTS environment:

Dim nonMTSObject
nonMTSObject = CreateObject ( "myactivex.myclass" )

The server will create the object in the same process as the ASP server, which is a benefit when using any object other than an MTS object.

One of the things that MUST be done, and is preferably to be done immediately after the last usage of the object, is to free up the memory used by the object. IIS frees this memory by using its garbage collector, but it seems that this garbage collector is not one of the best-optimized parts of IIS. By setting the object to Nothing, you release the object and the memory it refers.

Set myObject = Nothing ‘’ we clean up the memory.

If the component is an MTS object, the memory will be released and the component will be returned in the object pool of MTS, so other clients can reuse the object.

Optimizing memory and speed when working with Database Access Objects
Database access objects are one of the more used objects by the ASP programmers. They give you the possibility of interacting with the user in many ways, starting from background made statistics, which the user does not see, and which are made automatically when the user enters a page, to forms and information display.

Because of our laziness, we usually don‘’t think about cleaning up the mess that is left after our code has rune. We use ADO objects in lots of ways, starting from creating them in each page, or by creating them in the Application or Session objects, and getting them out of there every time.

One of the most mistakes made by ASP programmers is of putting instances of objects (usually the Connection object) in the Session Object. Each object reference that is created takes memory. If you don‘’t free up this memory, and you store it in the Session object, your web server will die slowly. It you have 500+ clients connected (in a short period of time, so the sessions don‘’t get closed) you will have problems with the memory of the server.

Instead of storing objects in the Session Object, recreate the object in each page. It‘’s faster and takes less memory. A better way to optimize database access is to use the capacity of connection pooling offered by ODBC 3.0+. Once a connection has been created and placed in a connection pool, an application can reuse that connection without paying the cost of opening a new database connection.

(If you have IIS 4.0 installed you for sure have ODBC 3.0 or later.)

Take the following code for example:

<%
Dim objADOConnection
Set objADOConnection = CreateObject ( "ADODB.Connection" )
objADOConnection.ActiveConnection = "DSN=TestDataBase"
Dim objADORecordSet
Set objADORecordSet = CreateObject ( "ADODB.RecordSet" )
objADORecordSet.Open "SELECT * FROM Table1" , objADOConnection
%>
<HTML>
<BODY>
<P>Elements of our table:</P>
<%
While NOT (objADORecordSet.EOF OR objADORecordSet.BOF)
Response.Write ( objADORecordSet.Fields ( 1 ).Value )
objADORecordSet.MoveNext
Wend
%>
</BODY>
</HTML>

This is a standard usage of the ADODB objects. We are creating a connection object, getting a recordset out of a table and then working with the recordset. Two great optimizations can be achieved in this code; a speed optimization and a memory optimization. ODBC 3.0 knows to pool database connections, and does this very well. So, the best way to optimize database access speed is to use the connection string, directly as the active connection. This way, we are not going to use a connection object any more. ODBC will get a database connection from its pool, and you will use a connection that was created earlier.

<%
Dim userDBConnectionString
userDBConnectionString = "DSN=TestDataBase"    ‘’ Name of the data source
Dim objADORecordSet
Set objADORecordSet = CreateObject ( "ADODB.RecordSet" )
objADORecordSet.Open "SELECT * FROM Table1" , userDBConnectionString
%>

Advantages: lots of speed improvements because we use only one object to retrieve data from the database, and we use the connection-pooling feature of ODBC, so we use an already open connection.

If you still want to use the Session object to store information about the database connection of the user, you can store the connection string in there, because there is only one change is needed if you change the data source name:

Session.Contents ("DataBaseConnection") = "DSN=TestDataBase"

And the code will become:

<%
Dim userDBConnectionString
userDBConnectionString = Session.Contents ("DataBaseConnection")
if userDBConnectionString = "" then
     ‘’ No DataBase Connection String was set before, so the user might
     ‘’ have entered on this page by using a direct url
     ‘’ We have two options:
     ‘’ 1 - redirect the user to a logon, or start page
     ‘’ 2 - open a default database connection
     ‘’ I prefere the first one
     Server. Response.Redirect ( "/MySite/LogonPage.asp" )
End if
Dim objADORecordSet
Set objADORecordSet = CreateObject ( "ADODB.RecordSet" )
objADORecordSet.Open "SELECT * FROM Table1" , userDBConnectionString
%>

The second optimization that can be done is the memory optimization. When dealing with huge ASP sites, which use lots of database connections, this optimization is more important than the speed optimization. By this you will also improve the speed of the web server.

Usually, we do nothing after using the ADO objects, we just let the ASP server "clean up". When CreateObject calls are made, resources are allocated on the server to handle instances of these objects. ASP will have to de-allocate the resources used by us, if we don‘’t explicitly inform the server that we are done using them. Putting all of our faith into ASP is a bit of a risk. It‘’s safer to explicitly close and cleanup the instances of our recordset and connection objects; essential on any large site.

What we have to do is to add the code to close and release the recordset, preferably immediately after the last usage of the objects:

<%
Dim userDBConnectionString
userDBConnectionString = Session.Contents ("DataBaseConnection")
if userDBConnectionString = "" then
     ‘’ No DataBase Connection String was set before, so the user might
     ‘’ have entered on this page by using a direct url
     ‘’ We have two options:
     ‘’ 1 - redirect the user to a logon, or start page
     ‘’ 2 - open a default database connection
     ‘’ I prefere the first one
     Server. Response.Redirect ( "/MySite/LogonPage.asp" )
End if
Dim objADORecordSet
Set objADORecordSet = CreateObject ( "ADODB.RecordSet" )
objADORecordSet.Open "SELECT * FROM Table1" , userDBConnectionString
%>
... display the records
<%
objADORecordSet.Close    ‘’ Close the recordset, so all records are released ‘’ from memory
Set objADORecordSet = Nothing ‘’ Release the instance of the recordset to
‘’ free memory
%>

If you are also using the connection object, than is mandatory to close and free this one too.

<%
objADOConnection.Close ‘’ Close the ADO connection, so you release the connection to the database
Set objADOConnection = Nothing ‘’ Release the instance of the connection to free memory
%>

This would be the most useful memory optimization of ASP pages. Don‘’t forget to clean up everything you use! You know the objects that have to be cleaned and how to clean their memory (first close, then release). IIS has to detect that.

Conclusion
IIS is a powerful web server, and used in combination with MTS object pooling and ODBC database connection pooling, it can give you a fast and useful web server. If you also optimize the ASP pages, IIS can get faster, and also help you to isolate problems like memory growing, page displaying speed, and eventually web server crashes. Part II of this article will talk mostly about optimizing speed by using different usage of date/time functions, conversion functions, string operations, lists and collection operations.

原文转自:http://www.ltesting.net