WCF REST サービス内で使用されている AutoMapper と StructureMap の使用でメモリ リークが発生しているようです。
ロード テストでは、メモリ使用量が継続的に増加していることがわかります。メモリ プロファイラを使用して詳しく調べたところ、MappingEngine の構築によって使用されるオブジェクトのインスタンスが多数あることがわかります (他のインスタンスの約 9 倍の量)。
Class Name=Live Instances
Object=498,847
Int32[]=69,373
Object[]=68,116
ConcurrentDictionary<TKey, TValue>+Node<TypePair, IObjectMapper>=37,624
string=35,240
IObjectMapper[]=30,782
EventHandler<TypeMapCreatedEventArgs>=30,782
MappingEngine=30,781
ConcurrentDictionary<TypePair, IObjectMapper>=30,781
ConcurrentDictionary<TKey, TValue>+Node<TypePair, LambdaExpression>[]=30,781
ConcurrentDictionary<TKey, TValue>+Node<TypePair, IObjectMapper>[]=30,781
ConcurrentDictionary<TypePair, LambdaExpression>=30,781
これが典型的なインスタンス保持グラフです...
bootstrapper._configuration
-> AutoMapper.ConfigurationStore (TypeMapCreated)
-> System.EventHandler<TypeMapCreatedEventArgs> (multicast delegate)
-> System.Object[]
-> System.EventHandler<TypeMapCreatedEventArgs>
-> AutoMapper.MappingEngine (_objectMapperCache)
-> System.Collections.Concurrent.ConcurrentDictionary<Internal.typePair, IObjectMapper> (m_locks)
-> System.Object[]
-> System.Object
(ゴミのフォーマットで申し訳ありませんが、画像を投稿できませんでした)
問題は、それが私のコード、StructureMap、または AutoMapper に問題があるかどうかわからないことです。
コードサンプル...
自動マップ用のブートストラップ (global.asax の Application_Start から呼び出される)...
public class BootStrapper
{
private static readonly IConfiguration _configuration = ObjectFactory.GetInstance<IConfiguration>();
public static void Initialize()
{
_configuration.AddProfile<AutoMapperProfile>();
}
public class AutoMapperProfile : Profile
{
protected override void Configure()
{
BootstrapAutoMapper();
}
}
public static void BootstrapAutoMapper()
{
_configuration.CreateMap<In.Account, Out.Accounts.Account>()
.ForMember(m => m.AccountNumber, o => o.MapFrom(s => s.AcctId))
.ForMember(m => m.Balances, o => o.Ignore())
.ForMember(m => m.AccountTypeDescription, o => o.MapFrom(s => s.TypeName))
.ForMember(m => m.AccountType, o => o.MapFrom(s => s.Type))
.ForMember(m => m.IsNoticeAccount, o => o.ResolveUsing(s => IsNoticeAccountMapper.Map(s.Type, ObjectFactory.GetInstance<IAccountTypeHelper>())));
// many other mappings excluded for brevity
}
}
StructureMap内で構成されています...
private void AutoMapperRegistration()
{
For<ConfigurationStore>().Singleton().Use<ConfigurationStore>().Ctor<IEnumerable<IObjectMapper>>().Is(AutoMapper.Mappers.MapperRegistry.AllMappers());
For<IConfigurationProvider>().Use(ctx => ctx.GetInstance<ConfigurationStore>());
For<IConfiguration>().Use(ctx => ctx.GetInstance<ConfigurationStore>());
For<ITypeMapFactory>().Use<TypeMapFactory>();
For<IMappingEngine>().Use<MappingEngine>();
Scan(scan =>
{
scan.AssemblyContainingType<AppRegistry>();
scan.AddAllTypesOf<Profile>();
});
}
典型的な WCF Rest サービスの使用法...
public class AccountService : IAccountService
{
private readonly IMappingEngine _mappingEngine;
private readonly IAccountFacade _accountFacade;
public AccountService(IMappingEngine mappingEngine, IAccountFacade accountFacade)
{
_mappingEngine = mappingEngine;
_accountFacade = accountFacade;
}
public IEnumerable<Account> GetAccounts()
{
var ret = new List<Account>();
var entities = _accountFacade.GetAccounts().ToList();
foreach (var account in entities.Select(entity => _mappingEngine.Map<In.Account, Out.Account>(entity)))
{
ret.Add(account);
}
return ret;
}
}