This article demonstrates how to create a console application that uses object pooling in Visual Basic .NET. You can turn on and turn off object pooling to see how object pooling affects an application that creates many expensive objects.back to the top Requirements
The following list outlines the recommended hardware, software, network infrastructure, and service packs that you need:
- Microsoft .NET Framework
- Microsoft Windows 2000 Professional, Microsoft Windows 2000 Server, Microsoft Windows XP Professional, or Microsoft Windows XP Server
This article assumes that you are familiar with the following topics:
back to the top Create a Console Application in Visual Basic .NET
- Component Object Model (COM) and Enterprise Services
- Object pooling
- Using attributes to extend metadata
back to the top Add a Poolable and a Non-Poolable Class to the Project
- Start Microsoft Visual Studio .NET.
- On the File menu, point to New, and then click New Project.
- In the New Project dialog box, click Visual Basic Projects under Project Types, and then click Console Application under Templates.
- In the Name text box, type PoolingDemo, and then click OK.
- Make sure that the Solution Explorer window is visible. If Solution Explorer is not visible, press the CTRL+ALT+L key combination.
- Follow these steps to add a reference to the COM component that you will be using:
- In Solution Explorer, right-click References, and then click Add Reference.
- On the .NET tab, click System.EnterpriseServices in the list of available components, and then click Select. Notice that System.EnterpriseServices appears in the Selected Components list.
- Click OK. Notice that System.EnterpriseServices appears under the References node in the console application.
back to the top Modify Module1.vb to Create Multiple Instances of These Classes
- Right-click PoolingDemo in Solution Explorer, point to Add, and then click Add New Item.
- In the Add New Item dialog box, click Class under Templates, and then click Open. Class1.vb is created by default and contains both poolable and non-poolable classes.
- To access object pooling attributes and members, add the following code to the top of Class1.vb:
- Replace the default Class1 declaration with the following code:
Notice that the constructor contains code that simulates an expensive operation.
Public Class Poolable Sub New() Threading.Thread.Sleep(500) End Sub Public Sub DoSomething() ' Add method contents here. End SubEnd Class
- The object must inherit the ServicedComponent class to come under the control of the Component Services runtime. Add the following code after the class declaration:
- To make this class poolable, follow these steps:
- The ObjectPoolingAttribute attribute, which is saved with the metadata of the class file, flags the object for pooling at run time. Add the following code above the Class declaration to add the ObjectPoolingAttribute attribute to the class:
NOTE: Although the JustInTimeActivation attribute is not required to enable pooling, you may want to use this attribute in most cases. Because it is expensive to create and to discard components, you can improve performance significantly by allowing multiple clients to reuse component instances.
<ObjectPooling(MinPoolSize:=0, MaxPoolSize:=1), JustInTimeActivation(True)> _
- The CanBePooledServicedComponent method returns False by default. To override the CanBePooled method so that the method returns True, add the following code:
Protected Overrides Function CanBePooled() As Boolean Return True End Function
- Add the following code to the non-poolable class:
Public Class NonPoolable Inherits ServicedComponent Sub New() ' Simulate an expensive operation. Threading.Thread.Sleep(500) End Sub Public Sub DoSomething() ' Add method contents here. End SubEnd Class
back to the top Generate a Strong Name for the Assembly
- In the Code Editor window, click the Module1.vb tab.
- At the top of the file, add the following Imports statement for the EnterpriseServices namespace to allow access to the DisposeObject method:
The DisposeOjbect method returns objects to the object pool, which allows them to be reused.
- Add the following Sub Main procedure:
This code sets up a loop that creates an instance of the NonPoolable or the Poolable class during each of its 50 iterations. The code records the start and the end times for the loop and then writes the number of objects that are created per second to the console.
Sub Main() Dim StartTime As DateTime = DateTime.Now Dim i As Int32 Const Iterations As Int16 = 50 For i = 1 To Iterations Dim D As New NonPoolable() D.DoSomething() ServicedComponent.DisposeObject(D) Next Dim EndTime As DateTime = DateTime.Now Dim Elapsed As TimeSpan = EndTime.Subtract(StartTime) Dim OperationsPerSecond = Iterations / Elapsed.TotalSeconds Console.WriteLine("Object Creations / Second = " & OperationsPerSecond) System.Console.ReadLine()End Sub
You must generate a strong name for the assembly that this project will generate. Without a strong name, you cannot use COM+ services to register this assembly.
To generate this cryptographic key pair, use the Strong Name (Sn.exe) tool, which is located in the Bin folder where the .NET Framework Software Development Kit (SDK) is installed. Use the following command-line syntax to run the Sn.exe tool:
sn -k drive letter\DirectoryToPlaceKey\KeyName.snk
back to the top Complete Code ListingsClass1.vb
- To open a Visual Studio .NET command prompt, click Start, point to Programs, point to Microsoft Visual Studio .NET, point to Visual Studio .NET Tools, and then click Visual Studio .NET Command Prompt.
- At the command prompt, type the following command:
sn -k drive letter:\Project Root Folder\poolkey.snk
- Press the ENTER key to generate the key pair. Notice that the following message appears in the command window:
Key pair written to...
- To associate this key with the project's assembly, double-click AssemblyInfo.vb in Solution Explorer. By default, Visual Studio .NET includes assembly attributes in this file when you create a project. Add the following code to this list of assembly attributes:
back to the top Module1.vb
Imports System.EnterpriseServices<ObjectPooling(MinPoolSize:=0, MaxPoolSize:=1), JustInTimeActivation(True)> _Public Class Poolable Inherits ServicedComponent Sub New() ' Simulate an expensive operation. Threading.Thread.Sleep(500) End Sub Public Sub DoSomething() ' Add method contents here. End Sub Protected Overrides Function CanBePooled() As Boolean Return True End FunctionEnd ClassPublic Class NonPoolable Inherits ServicedComponent Sub New() ' Simulate an expensive operation. Threading.Thread.Sleep(500) End Sub Public Sub DoSomething() ' Add method contents here. End SubEnd Class
back to the top AssemblyInfo.vb
Imports System.EnterpriseServicesModule Module1 Sub Main() Dim StartTime As DateTime = DateTime.Now Dim i As Int32 Const Iterations As Int16 = 50 For i = 1 To Iterations 'Dim D As New Poolable() Dim D As New NonPoolable() D.DoSomething() ' To return the object to the object pool, use DisposeObject. ' This allows the object to be reused from the pool. If you do not call ' DisposeObject, the garbage collector does not collect this object, ' and the object is not reused from the object pool. ServicedComponent.DisposeObject(D) Next Dim EndTime As DateTime = DateTime.Now Dim Elapsed As TimeSpan = EndTime.Subtract(StartTime) Dim OperationsPerSecond = Iterations / Elapsed.TotalSeconds Console.WriteLine("Object Creations / Second = " & OperationsPerSecond) ' Pause until the user presses ENTER. System.Console.ReadLine() End SubEnd Module
back to the top Verify That It Works
Imports System.ReflectionImports System.Runtime.InteropServices' The following set of attributes control general information about an assembly. ' Change these attribute values to modify the information that is associated with an assembly.' Review the values of the assembly attributes.<Assembly: AssemblyTitle("")> <Assembly: AssemblyDescription("")> <Assembly: AssemblyCompany("")> <Assembly: AssemblyProduct("")> <Assembly: AssemblyCopyright("")> <Assembly: AssemblyTrademark("")> <Assembly: CLSCompliant(True)> <Assembly: AssemblyKeyFile("..\..\poolkey.snk")> 'The following GUID is for the ID of the TypeLib if you expose this project to COM.<Assembly: Guid("30324ED6-329C-4B12-BDA2-8E817F1E2079")> ' Version information for an assembly consists of the following four values:'' Major Version' Minor Version ' Build Number' Revision'' You can specify all of these values, or you can use the asterisk (*) for' the Build Number and the Revision values.<Assembly: AssemblyVersion("1.0.*")>
back to the top Troubleshooting
- Press the F5 key to run the application in debug mode. Notice that this creates instances of the NonPoolable class.
- Wait approximately 25 seconds. Notice that the following message appears:
Object Creations / Second = 1.73542243764044NOTE: The exact number of creations per second may vary.
- Press ENTER to exit the console application and to return to Visual Studio .NET.
- Modify Module1.vb to create instances of the Poolable class. Change the first line in the Sub Main procedure as follows:
- Press F5 to run the application again.
- Wait a few seconds. Notice that the following message (or similar) appears:
Object Creations / Second = 29.1977213631085 Note the significant improvement in performance when you use object pooling.
- Press ENTER to exit the console application and to return to Visual Studio .NET.
Do not forget to override CanBePooled
. If you omit this step, you cannot pool the object.back to the top REFERENCES
For more information about how to implement and deploy COM+ configured classes by using the common language runtime, how to access object context and call context, and how to manage context-relative object references, refer to the following Microsoft Web site: back to the top