Category Archives: Performance

SPLwow64.exe Terminal Server/Remote Desktop Service tweak needed

Now having had two clients with a related system process problem, I am documenting what I’ve discovered and the needed tweak to fix it.  Both of these small businesses are heavily using Remote Desktop Services aka Terminal Server.  One with SBS 2011 and Windows 2008 R2 on the member server (both virtualized on Hyper-V); the other uses SBS 2008 with Windows 2008 on its member server.  The first biz uses 98% of its connections as thin clients and has seen huge amounts of memory (commit size) set aside for instances of ‘splwow64.exe’.  The second client experienced an issue with Windows 2000 clients (yes they are still out there …yikes!) not automatically ending their session when they closed the Environment Tab specified application that their TS session is limited to running/displaying – just got the blue logoff screen in a hung stasis.

On the first I tried changing the configuration of the main shared printer.  The printer is which I determined was where all the SPLwow64.exe related print tasks were being sent.  First I disabled spooling and secondly I unchecked the box to render print jobs on client (in this case the RDS server).  Neither satisfied the desired memory release I wanted to see achieved.  I could confirm the correlation with the SPLwow64.exe process and actual memory consumed via the Hyper-V Manager console which showed the dynamic memory demand of this RDS machine.  When the topmost listed instances of the SPLwow64.exe process were ‘ended’ the overall memory dropped equally dramatically.  This server which typically needed roughly 4 GB of running memory was underperforming when maxing out at 10 GB that were dynamically being made available to it.

The link below states in the first post that you can adjust the time this process takes to release its memory and links to a dead KB article.

That applicable control registry key is:



The second client’s issue led me to find the following thread and and in the last post the solution.  It’s a simple technique that can be applied if you want to turn off the use of system processes, SYSwow64.exe in this case, for a Terminal Server.

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\SysProcs
Add a REG_DWORD called "splwow64.exe" set the value to 0


**Here’s another related conversation thread by an application developer found in the private Microsoft Forums


Boot INI Options Reference

Was researching the 3GB switch that could be used in the boot.ini file to extend Windows 2003 to more fully utilize memory when more than 3GB exists (think pre x64 days) – This is not recommended to be used with SBS and the SBS BPA will call your attention to this as is the case with why I did this research.

Overall this is a handy guide for many switch options.

Boot INI Options Reference

Mark Russinovich

Published: November 1, 2006


There are number of BOOT.INI switches that are useful for driver developers that wish to test their drivers under a variety of different system configurations without having to have a separate machine for every one. For example, limiting the amount of memory NT sees can be useful for stressing memory loads, and limiting the number of processors for testing scalability. I’ve compiled a complete list of the options that BOOT.INI currently supports. This list is reproduced in the Startup, Shutdown and Crashes chapter of Windows Internals, where you’ll find more information about the boot process.

Note: to see what options a system has booted with examine HKLM\System\CurrentControlSet\Control\SystemStartOptions.

Boot INI Options Reference

BITS Peer Caching – many clients only one Windows Update download – WSUS optimization

Inside the WSUS 3.0 SP2 Operations Guide document in Appendix E (p123) I found this very cool nugget.  This applies to WSUS deployments where updates are not downloaded, stored, and distributed locally.

Assuming all the clients are online and scheduled to query and sync for Windows Updates (WSUS, WU, MU) together you could greatly benefit from only downloading a patch once.  For my peers in Australia who pay for bandwidth used this may be quite valuable.

Peer caching

Peer caching is a new feature of BITS 3.0 that allows peers (computers within the same subnet of a network that have the peer caching feature enabled) to share files. If peer caching is enabled on a computer, the Automatic Update agent instructs BITS to make downloaded files available to that computer’s peers as well.

When the files have been downloaded, BITS caches them. When another (peer caching-enabled) computer tries to download the same update, BITS on that computer sends a multicast request to all of that computer’s peers. If one or more of the peers responds to the request, BITS will download the file from the first computer to respond. If the download from the peer fails or take too long, BITS continues the download from the WSUS server or Microsoft Update.

This feature of BITS can optimize the bandwidth used by WSUS in several ways.

1. Peer caching decreases the amount of data transferred from the WSUS server to its clients, because computers in the same subnet will usually download the updates from each other.

2. Peer caching decreases the amount of data transferred across the WAN when some or all of the clients of a WSUS server are located in different locations.

3. Peer caching decreases the amount of data transferred across the Internet if WSUS clients in the same subnet are configured to download updates from Microsoft Update.


BITS peer caching requires computers to be running Windows Vista or Windows Server 2008, and to be part of an Active Directory Domain.

For more information about peer caching and peer servers, see Peer Caching (

To enable peer caching (on Windows Vista)

1. Start the Group Policy Object Editor (click Start, click Run, and then type gpedit.msc).

2. Expand Computer Configuration, then Administrative Templates, then Network, then Background Intelligent Transfer Service.

3. Enable the Allow BITS Peercaching setting.

4. Enable the Maximum network bandwidth used for Peercaching setting, and set the maximum bandwidth in bits per second (the default is 104857), then click OK.

5. Enable the Limit the BITS Peercache size setting, and set the percentage of disk space to be used for the peer cache (the default is 5 percent), and then click OK.

6. Enable the Limit age of items in the BITs Peercache setting, and set the number of days (the default is 90), and then click OK.


You must be an administrator to perform this procedure.

**author note**  besides modifying the applicable GPO on Vista you could also do this from a Server 2008 server.  Vista is the first client OS to provide domain scope GPO management.

Re-index the WSUS 3.0 Database via a GUI

Combining forces and ideas you can use the scripting provided by TechNet with my blog post on using the SQL Server Management Studio Express (SSMSE 2005) to get this maintenance task done easily.  When done your WSUS database will be healthy and far more responsive.

This can have a significant beneficial impact when you consider how the clients submit sync queries to the WSUS 3.0 server especially at startup.  Be prepared for this script to run from anywhere between 5-30 minutes depending on amount of work needing done to get things to good health. Use at your own risk. Script below is copied from the TechNet source.

TechNet script source and info (recommending reading once before using script):

This sample T-SQL script performs basic maintenance tasks on SUSDB
1. Identifies indexes that are fragmented and defragments them. For certain
tables, a fill-factor is set in order to improve insert performance.
Based on MSDN sample at
and tailored for SUSDB requirements
2. Updates potentially out-of-date table statistics.


-- Rebuild or reorganize indexes based on their fragmentation levels
DECLARE @work_to_do TABLE (
objectid int
, indexid int
, pagedensity float
, fragmentation float
, numrows int

DECLARE @objectid int;
DECLARE @indexid int;
DECLARE @schemaname nvarchar(130);
DECLARE @objectname nvarchar(130);
DECLARE @indexname nvarchar(130);
DECLARE @numrows int
DECLARE @density float;
DECLARE @fragmentation float;
DECLARE @command nvarchar(4000);
DECLARE @fillfactorset bit
DECLARE @numpages int

-- Select indexes that need to be defragmented based on the following
-- * Page density is low
-- * External fragmentation is high in relation to index size
PRINT 'Estimating fragmentation: Begin. ' + convert(nvarchar, getdate(), 121)
INSERT @work_to_do
, index_id
, avg_page_space_used_in_percent
, avg_fragmentation_in_percent
, record_count
sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, 'SAMPLED') AS f
(f.avg_page_space_used_in_percent < 85.0 and f.avg_page_space_used_in_percent/100.0 * page_count 50 and f.avg_fragmentation_in_percent > 15.0)
or (f.page_count > 10 and f.avg_fragmentation_in_percent > 80.0)

PRINT 'Number of indexes to rebuild: ' + cast(@@ROWCOUNT as nvarchar(20))

PRINT 'Estimating fragmentation: End. ' + convert(nvarchar, getdate(), 121)

SELECT @numpages = sum(ps.used_page_count)
@work_to_do AS fi
INNER JOIN sys.indexes AS i ON fi.objectid = i.object_id and fi.indexid = i.index_id
INNER JOIN sys.dm_db_partition_stats AS ps on i.object_id = ps.object_id and i.index_id = ps.index_id

-- Declare the cursor for the list of indexes to be processed.
DECLARE curIndexes CURSOR FOR SELECT * FROM @work_to_do

-- Open the cursor.
OPEN curIndexes

-- Loop through the indexes
WHILE (1=1)
INTO @objectid, @indexid, @density, @fragmentation, @numrows;

@objectname = QUOTENAME(
, @schemaname = QUOTENAME(
sys.objects AS o
INNER JOIN sys.schemas as s ON s.schema_id = o.schema_id
o.object_id = @objectid;

@indexname = QUOTENAME(name)
, @fillfactorset = CASE fill_factor WHEN 0 THEN 0 ELSE 1 END
object_id = @objectid AND index_id = @indexid;

IF ((@density BETWEEN 75.0 AND 85.0) AND @fillfactorset = 1) OR (@fragmentation = 5000 AND @fillfactorset = 0
SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REBUILD WITH (FILLFACTOR = 90)';
SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REBUILD';
PRINT convert(nvarchar, getdate(), 121) + N' Executing: ' + @command;
EXEC (@command);
PRINT convert(nvarchar, getdate(), 121) + N' Done.';

-- Close and deallocate the cursor.
CLOSE curIndexes;
DEALLOCATE curIndexes;

IF EXISTS (SELECT * FROM @work_to_do)
PRINT 'Estimated number of pages in fragmented indexes: ' + cast(@numpages as nvarchar(20))
SELECT @numpages = @numpages - sum(ps.used_page_count)
@work_to_do AS fi
INNER JOIN sys.indexes AS i ON fi.objectid = i.object_id and fi.indexid = i.index_id
INNER JOIN sys.dm_db_partition_stats AS ps on i.object_id = ps.object_id and i.index_id = ps.index_id

PRINT 'Estimated number of pages freed: ' + cast(@numpages as nvarchar(20))

--Update all statistics
PRINT 'Updating all statistics.' + convert(nvarchar, getdate(), 121)
EXEC sp_updatestats
PRINT 'Done updating statistics.' + convert(nvarchar, getdate(), 121)

Blog on Connected to Windows Internal Database with SSMSE via named pipes:

Another helpful tool is to identify which version of SQL your database actually is.  Is it SQL or Windows Internal Database?

The Official SBS Blog : Allocated Memory Errors After Adding RAM

A quick reference point to deal with the ever present SBS Critical Alert that warns of memory allocation gone awry.  In truth the Health Monitor threshold most likely just needs to match the correct amount of memory you installed is it is anything above 2GB.  Kudos again to the Official SBS Blog which I have a linked feed on the right of this blog.

The short version of the solution is to change the threshold according to these instructions:

To modify the value, do the following:

1.  Click START -> Administrator Tools -> Health Monitor

2.  Navigate to Health Monitor -> All Monitored Computers -> SBSSERVER -> Small Business Server Alerts -> Core Server Alerts -> Allocated Memory.  On the right-hand pane, right-click on “Allocated Memory” and choose Properties.  Edit the “is greater than” value to reflect the correct amount of RAM.  Default is 2 GB/2147483648 (3 GB = 3221225472, 4 GB = 4294967296).

Allocated Memory Errors After Adding RAM

The Official SBS Blog : Allocated Memory Errors After Adding RAM