Merge pull request #2264 from dotnet/pakrym/dc-memory

Optimize dependency context memory usage
This commit is contained in:
Pavel Krymets 2016-05-16 10:50:41 -07:00
commit 07b785c183
3 changed files with 71 additions and 37 deletions

View file

@ -12,6 +12,8 @@ namespace Microsoft.Extensions.DependencyModel
{ {
public class DependencyContextJsonReader : IDependencyContextReader public class DependencyContextJsonReader : IDependencyContextReader
{ {
private readonly IDictionary<string, string> _stringPool = new Dictionary<string, string>();
public DependencyContext Read(Stream stream) public DependencyContext Read(Stream stream)
{ {
if (stream == null) if (stream == null)
@ -28,6 +30,19 @@ namespace Microsoft.Extensions.DependencyModel
} }
} }
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
_stringPool.Clear();
}
}
public void Dispose()
{
Dispose(true);
}
private bool IsRuntimeTarget(string name) => name.Contains(DependencyContextStrings.VersionSeperator); private bool IsRuntimeTarget(string name) => name.Contains(DependencyContextStrings.VersionSeperator);
private DependencyContext Read(JObject root) private DependencyContext Read(JObject root)
@ -178,8 +193,8 @@ namespace Microsoft.Extensions.DependencyModel
var seperatorPosition = nameWithVersion.IndexOf(DependencyContextStrings.VersionSeperator); var seperatorPosition = nameWithVersion.IndexOf(DependencyContextStrings.VersionSeperator);
var name = nameWithVersion.Substring(0, seperatorPosition); var name = Pool(nameWithVersion.Substring(0, seperatorPosition));
var version = nameWithVersion.Substring(seperatorPosition + 1); var version = Pool(nameWithVersion.Substring(seperatorPosition + 1));
var libraryObject = (JObject)property.Value; var libraryObject = (JObject)property.Value;
@ -263,13 +278,13 @@ namespace Microsoft.Extensions.DependencyModel
foreach (var resourceProperty in resourcesObject) foreach (var resourceProperty in resourcesObject)
{ {
yield return new ResourceAssembly( yield return new ResourceAssembly(
locale: resourceProperty.Value[DependencyContextStrings.LocalePropertyName]?.Value<string>(), locale: Pool(resourceProperty.Value[DependencyContextStrings.LocalePropertyName]?.Value<string>()),
path: resourceProperty.Key path: resourceProperty.Key
); );
} }
} }
private static IEnumerable<RuntimeTargetEntryStub> ReadRuntimeTargetEntries(JObject runtimeTargetObject) private IEnumerable<RuntimeTargetEntryStub> ReadRuntimeTargetEntries(JObject runtimeTargetObject)
{ {
if (runtimeTargetObject == null) if (runtimeTargetObject == null)
{ {
@ -281,8 +296,8 @@ namespace Microsoft.Extensions.DependencyModel
yield return new RuntimeTargetEntryStub() yield return new RuntimeTargetEntryStub()
{ {
Path = libraryProperty.Key, Path = libraryProperty.Key,
Rid = libraryObject[DependencyContextStrings.RidPropertyName].Value<string>(), Rid = Pool(libraryObject[DependencyContextStrings.RidPropertyName].Value<string>()),
Type = libraryObject[DependencyContextStrings.AssetTypePropertyName].Value<string>() Type = Pool(libraryObject[DependencyContextStrings.AssetTypePropertyName].Value<string>())
}; };
} }
} }
@ -299,7 +314,7 @@ namespace Microsoft.Extensions.DependencyModel
return assembliesObject.Properties().Select(property => property.Name).ToArray(); return assembliesObject.Properties().Select(property => property.Name).ToArray();
} }
private static Dependency[] ReadDependencies(JObject libraryObject) private Dependency[] ReadDependencies(JObject libraryObject)
{ {
var dependenciesObject = (JObject)libraryObject[DependencyContextStrings.DependenciesPropertyName]; var dependenciesObject = (JObject)libraryObject[DependencyContextStrings.DependenciesPropertyName];
@ -309,7 +324,7 @@ namespace Microsoft.Extensions.DependencyModel
} }
return dependenciesObject.Properties() return dependenciesObject.Properties()
.Select(property => new Dependency(property.Name, (string)property.Value)).ToArray(); .Select(property => new Dependency(Pool(property.Name), Pool((string)property.Value))).ToArray();
} }
private Dictionary<string, LibraryStub> ReadLibraryStubs(JObject librariesObject) private Dictionary<string, LibraryStub> ReadLibraryStubs(JObject librariesObject)
@ -322,9 +337,9 @@ namespace Microsoft.Extensions.DependencyModel
var value = (JObject)libraryProperty.Value; var value = (JObject)libraryProperty.Value;
var stub = new LibraryStub var stub = new LibraryStub
{ {
Name = libraryProperty.Key, Name = Pool(libraryProperty.Key),
Hash = value[DependencyContextStrings.Sha512PropertyName]?.Value<string>(), Hash = value[DependencyContextStrings.Sha512PropertyName]?.Value<string>(),
Type = value[DependencyContextStrings.TypePropertyName].Value<string>(), Type = Pool(value[DependencyContextStrings.TypePropertyName].Value<string>()),
Serviceable = value[DependencyContextStrings.ServiceablePropertyName]?.Value<bool>() == true Serviceable = value[DependencyContextStrings.ServiceablePropertyName]?.Value<bool>() == true
}; };
libraries.Add(stub.Name, stub); libraries.Add(stub.Name, stub);
@ -333,6 +348,22 @@ namespace Microsoft.Extensions.DependencyModel
return libraries; return libraries;
} }
private string Pool(string s)
{
if (s == null)
{
return null;
}
string result;
if (!_stringPool.TryGetValue(s, out result))
{
_stringPool[s] = s;
result = s;
}
return result;
}
private struct RuntimeTargetEntryStub private struct RuntimeTargetEntryStub
{ {
public string Type; public string Type;

View file

@ -16,13 +16,13 @@ namespace Microsoft.Extensions.DependencyModel
private readonly string _entryPointDepsLocation; private readonly string _entryPointDepsLocation;
private readonly string _runtimeDepsLocation; private readonly string _runtimeDepsLocation;
private readonly IFileSystem _fileSystem; private readonly IFileSystem _fileSystem;
private readonly IDependencyContextReader _jsonReader; private readonly Func<IDependencyContextReader> _jsonReaderFactory;
public DependencyContextLoader() : this( public DependencyContextLoader() : this(
DependencyContextPaths.Current.Application, DependencyContextPaths.Current.Application,
DependencyContextPaths.Current.SharedRuntime, DependencyContextPaths.Current.SharedRuntime,
FileSystemWrapper.Default, FileSystemWrapper.Default,
new DependencyContextJsonReader()) () => new DependencyContextJsonReader())
{ {
} }
@ -30,12 +30,12 @@ namespace Microsoft.Extensions.DependencyModel
string entryPointDepsLocation, string entryPointDepsLocation,
string runtimeDepsLocation, string runtimeDepsLocation,
IFileSystem fileSystem, IFileSystem fileSystem,
IDependencyContextReader jsonReader) Func<IDependencyContextReader> jsonReaderFactory)
{ {
_entryPointDepsLocation = entryPointDepsLocation; _entryPointDepsLocation = entryPointDepsLocation;
_runtimeDepsLocation = runtimeDepsLocation; _runtimeDepsLocation = runtimeDepsLocation;
_fileSystem = fileSystem; _fileSystem = fileSystem;
_jsonReader = jsonReader; _jsonReaderFactory = jsonReaderFactory;
} }
public static DependencyContextLoader Default { get; } = new DependencyContextLoader(); public static DependencyContextLoader Default { get; } = new DependencyContextLoader();
@ -58,61 +58,63 @@ namespace Microsoft.Extensions.DependencyModel
} }
DependencyContext context = null; DependencyContext context = null;
using (var reader = _jsonReaderFactory())
if (IsEntryAssembly(assembly))
{ {
context = LoadEntryAssemblyContext(); if (IsEntryAssembly(assembly))
}
if (context == null)
{
context = LoadAssemblyContext(assembly);
}
if (context?.Target.IsPortable == true)
{
var runtimeContext = LoadRuntimeContext();
if (runtimeContext != null)
{ {
context = context.Merge(runtimeContext); context = LoadEntryAssemblyContext(reader);
}
if (context == null)
{
context = LoadAssemblyContext(assembly, reader);
}
if (context?.Target.IsPortable == true)
{
var runtimeContext = LoadRuntimeContext(reader);
if (runtimeContext != null)
{
context = context.Merge(runtimeContext);
}
} }
} }
return context; return context;
} }
private DependencyContext LoadEntryAssemblyContext() private DependencyContext LoadEntryAssemblyContext(IDependencyContextReader reader)
{ {
if (!string.IsNullOrEmpty(_entryPointDepsLocation)) if (!string.IsNullOrEmpty(_entryPointDepsLocation))
{ {
Debug.Assert(File.Exists(_entryPointDepsLocation)); Debug.Assert(File.Exists(_entryPointDepsLocation));
using (var stream = _fileSystem.File.OpenRead(_entryPointDepsLocation)) using (var stream = _fileSystem.File.OpenRead(_entryPointDepsLocation))
{ {
return _jsonReader.Read(stream); return reader.Read(stream);
} }
} }
return null; return null;
} }
private DependencyContext LoadRuntimeContext() private DependencyContext LoadRuntimeContext(IDependencyContextReader reader)
{ {
if (!string.IsNullOrEmpty(_runtimeDepsLocation)) if (!string.IsNullOrEmpty(_runtimeDepsLocation))
{ {
Debug.Assert(File.Exists(_runtimeDepsLocation)); Debug.Assert(File.Exists(_runtimeDepsLocation));
using (var stream = _fileSystem.File.OpenRead(_runtimeDepsLocation)) using (var stream = _fileSystem.File.OpenRead(_runtimeDepsLocation))
{ {
return _jsonReader.Read(stream); return reader.Read(stream);
} }
} }
return null; return null;
} }
private DependencyContext LoadAssemblyContext(Assembly assembly) private DependencyContext LoadAssemblyContext(Assembly assembly, IDependencyContextReader reader)
{ {
using (var stream = GetResourceStream(assembly, assembly.GetName().Name + DepsJsonExtension)) using (var stream = GetResourceStream(assembly, assembly.GetName().Name + DepsJsonExtension))
{ {
if (stream != null) if (stream != null)
{ {
return _jsonReader.Read(stream); return reader.Read(stream);
} }
} }
@ -121,7 +123,7 @@ namespace Microsoft.Extensions.DependencyModel
{ {
using (var stream = _fileSystem.File.OpenRead(depsJsonFile)) using (var stream = _fileSystem.File.OpenRead(depsJsonFile))
{ {
return _jsonReader.Read(stream); return reader.Read(stream);
} }
} }

View file

@ -1,8 +1,9 @@
using System;
using System.IO; using System.IO;
namespace Microsoft.Extensions.DependencyModel namespace Microsoft.Extensions.DependencyModel
{ {
public interface IDependencyContextReader public interface IDependencyContextReader: IDisposable
{ {
DependencyContext Read(Stream stream); DependencyContext Read(Stream stream);
} }