How do I clean up the SQL Server to get rid of expired SqlDependency
objects? After I receive the event from the SqlDepedency
object, I need to create a new one before I can get a new event. However, the memory use of the SQL Server process climbs until it runs out of the allowed memory (SQL Server Express). How do I get rid of old queries?
Code:
// Func: RegisterTableListener
using (SqlConnection cn = new SqlConnection(Properties.Settings.Default.DatabseEventConnectionString))
{
if (cmd == null)
{
cmd = cn.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = "SELECT HostName, LastStatus, LastDetails, xml FROM dbo.[SystemTable]";
}
lock (cmd)
{
cmd.Connection = cn;
cn.Open();
cmd.Notification = null;
// creates a new dependency for the SqlCommand
if (dep == null)
dep = new SqlDependency(cmd);
// creates an event handler for the notification of data
// changes in the database.
dep.OnChange += new OnChangeEventHandler(dependency_OnChange);
using (SqlDataReader reader = cmd.ExecuteReader())
{
// code here to read
}
}
}
// Func dependency_OnChange
//SqlDependency dep = sender as SqlDependency;
dep.OnChange -= dependency_OnChange;
RegisterTableListener();
To free up the memory used by sql server, I ran DBCC FREESYSTEMCACHE, FREEPROCCACHE, DROPCLEANBUFFERS and I closed the existing sessions, closed SSMS and opened it again but the memory was not released. I restarted the server and the issue was solved.
SQL Server will consume all of the available memory. By default, that number corresponds to the total amount of numeric memory available on your computer. As a result, your perceptions are correct. To put it another way, if you give SQL Server 24 GB of memory, it will make every effort to make the most of that memory.
dm_os_process_memory; A solution is to drop max server memory for the SQL Server and increase it again to force SQL Server to release unused but allocated memory.
There is a specific behavior of Microsoft SqlDependency class. Even though you call SqlDependency.Stop() method, release SqlCommand and SqlConnection - it still keeps conversation groups (sys.conversation_groups) and conversation endpoints (sys.conversation_endpoints) in the database. It looks like SQL Server loads every conversation endpoint and uses all allowed memory. Here tests that prove it. So, to clean all unused conversation endpoints and release all occupied memory you have to start this SQL code for your database:
DECLARE @ConvHandle uniqueidentifier
DECLARE Conv CURSOR FOR
SELECT CEP.conversation_handle FROM sys.conversation_endpoints CEP
WHERE CEP.state = 'DI' or CEP.state = 'CD'
OPEN Conv;
FETCH NEXT FROM Conv INTO @ConvHandle;
WHILE (@@FETCH_STATUS = 0) BEGIN
END CONVERSATION @ConvHandle WITH CLEANUP;
FETCH NEXT FROM Conv INTO @ConvHandle;
END
CLOSE Conv;
DEALLOCATE Conv;
Also, SqlDependency doesn't give you an opportunity to receive ALL changes of the table. So, you don't receive notification about changes during SqlDependency resubscription.
To avoid all these problems I'd used another open source realization of SqlDependency class - SqlDependencyEx. It uses database trigger and native Service Broker notification to receive events about changes of the table. This is an usage example:
int changesReceived = 0;
using (SqlDependencyEx sqlDependency = new SqlDependencyEx(
TEST_CONNECTION_STRING, TEST_DATABASE_NAME, TEST_TABLE_NAME))
{
sqlDependency.TableChanged += (o, e) => changesReceived++;
sqlDependency.Start();
// Make table changes.
MakeTableInsertDeleteChanges(changesCount);
// Wait a little bit to receive all changes.
Thread.Sleep(1000);
}
Assert.AreEqual(changesCount, changesReceived);
Hope this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With