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
{
private readonly IDictionary<string, string> _stringPool = new Dictionary<string, string>();
public DependencyContext Read(Stream stream)
{
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 DependencyContext Read(JObject root)
@ -178,8 +193,8 @@ namespace Microsoft.Extensions.DependencyModel
var seperatorPosition = nameWithVersion.IndexOf(DependencyContextStrings.VersionSeperator);
var name = nameWithVersion.Substring(0, seperatorPosition);
var version = nameWithVersion.Substring(seperatorPosition + 1);
var name = Pool(nameWithVersion.Substring(0, seperatorPosition));
var version = Pool(nameWithVersion.Substring(seperatorPosition + 1));
var libraryObject = (JObject)property.Value;
@ -263,13 +278,13 @@ namespace Microsoft.Extensions.DependencyModel
foreach (var resourceProperty in resourcesObject)
{
yield return new ResourceAssembly(
locale: resourceProperty.Value[DependencyContextStrings.LocalePropertyName]?.Value<string>(),
locale: Pool(resourceProperty.Value[DependencyContextStrings.LocalePropertyName]?.Value<string>()),
path: resourceProperty.Key
);
}
}
private static IEnumerable<RuntimeTargetEntryStub> ReadRuntimeTargetEntries(JObject runtimeTargetObject)
private IEnumerable<RuntimeTargetEntryStub> ReadRuntimeTargetEntries(JObject runtimeTargetObject)
{
if (runtimeTargetObject == null)
{
@ -281,8 +296,8 @@ namespace Microsoft.Extensions.DependencyModel
yield return new RuntimeTargetEntryStub()
{
Path = libraryProperty.Key,
Rid = libraryObject[DependencyContextStrings.RidPropertyName].Value<string>(),
Type = libraryObject[DependencyContextStrings.AssetTypePropertyName].Value<string>()
Rid = Pool(libraryObject[DependencyContextStrings.RidPropertyName].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();
}
private static Dependency[] ReadDependencies(JObject libraryObject)
private Dependency[] ReadDependencies(JObject libraryObject)
{
var dependenciesObject = (JObject)libraryObject[DependencyContextStrings.DependenciesPropertyName];
@ -309,7 +324,7 @@ namespace Microsoft.Extensions.DependencyModel
}
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)
@ -322,9 +337,9 @@ namespace Microsoft.Extensions.DependencyModel
var value = (JObject)libraryProperty.Value;
var stub = new LibraryStub
{
Name = libraryProperty.Key,
Name = Pool(libraryProperty.Key),
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
};
libraries.Add(stub.Name, stub);
@ -333,6 +348,22 @@ namespace Microsoft.Extensions.DependencyModel
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
{
public string Type;

View file

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

View file

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