-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Description
Hello, when using connection.BeginTransaction, the below code will cause memory leak:
public static ICapTransaction BeginTransaction(this IDbConnection dbConnection, ICapPublisher publisher, bool autoCommit = false)
{
if (dbConnection.State == ConnectionState.Closed)
{
dbConnection.Open();
}
var dbTransaction = dbConnection.BeginTransaction();
publisher.Transaction.Value = publisher.ServiceProvider.GetService<ICapTransaction>();
return publisher.Transaction.Value.Begin(dbTransaction, autoCommit);
}ICapPublisher is registered as singleton, ICapTransaction is registered as transient; you create transient object(ICapTransaction) by singleton object(ServiceProvider), and the transient object(ICapTransaction) implements IDisposable, so the transient object(ICapTransaction) will never GC because the IOC container is not released.
I simulate 100000+ calls to the action AdonetWithTransaction, see the below code:
[Route("~/adonet/transaction")]
public IActionResult AdonetWithTransaction()
{
using (var connection = new MySqlConnection(AppDbContext.ConnectionString))
{
using (var transaction = connection.BeginTransaction(_capBus, true))
{
//your business code
}
}
return Ok();
}Then I turn on VS diagnostics tools to monitor memory changes, I found the objects that inherit ICapTransaction will persist in memory,see below:

You can use ActivatorUtilities.GetServiceOrCreateInstance to create transient object(ICapTransaction) in method connection.BeginTransaction