Skip to content

Commit f9ad560

Browse files
committed
Allow full size images to be garbage-collected.
Use a weak reference to get them back if they're needed again before the GC eats them. Also use a MemoryCache to ensure they're kept around for at least 10 seconds.
1 parent 62ccc9b commit f9ad560

File tree

3 files changed

+54
-8
lines changed

3 files changed

+54
-8
lines changed

PhotoTagger.Imaging/ImageLoadManager.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ public void EnqueueLoad(Photo photo,
2525
makeIOThread();
2626
}
2727

28+
internal void EnqueueFullSizeRead(Photo photo, Photo.Metadata meta) {
29+
fullsizeReads.Add(new Tuple<Photo, Photo.Metadata>(photo, meta));
30+
makeIOThread();
31+
}
32+
2833
private BlockingCollection<Tuple<Photo, ObservableCollection<Photo>>> metadataReads =
2934
new BlockingCollection<Tuple<Photo, ObservableCollection<Photo>>>();
3035

@@ -135,16 +140,15 @@ private async Task loadMeta(Photo photo,
135140
mmap.Dispose();
136141
throw;
137142
}
138-
if (await photo.Dispatcher.InvokeAsync(() => {
143+
if (!await photo.Dispatcher.InvokeAsync(() => {
139144
if (photo.Disposed) {
140145
return false;
141146
}
142147
photo.mmap = mmap;
148+
photo.loader = this;
143149
photo.ThumbImage = img;
144150
return true;
145151
})) {
146-
fullsizeReads.Add(new Tuple<Photo, Photo.Metadata>(photo, metadata));
147-
} else {
148152
mmap.Dispose();
149153
}
150154
} catch (Exception ex) {

PhotoTagger.Imaging/Photo.cs

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.ComponentModel;
33
using System.Diagnostics.Contracts;
44
using System.IO.MemoryMappedFiles;
5+
using System.Runtime.Caching;
56
using System.Threading;
67
using System.Threading.Tasks;
78
using System.Windows;
@@ -14,24 +15,61 @@ public Photo(string f) {
1415
this.ShortTitle = f;
1516
}
1617

18+
private WeakReference<BitmapImage> fullImageRef = null;
19+
20+
private int fullIsLoading = 0;
21+
22+
private static CacheItemPolicy cachePolicy = new CacheItemPolicy() {
23+
SlidingExpiration = TimeSpan.FromSeconds(10),
24+
};
25+
1726
public BitmapImage FullImage {
1827
get {
19-
return (BitmapImage)GetValue(FullImageProperty);
28+
var imageRef = this.fullImageRef;
29+
if (imageRef != null && imageRef.TryGetTarget(out BitmapImage target)) {
30+
MemoryCache.Default.Set(
31+
this.FileName,
32+
target,
33+
cachePolicy);
34+
return target;
35+
} else {
36+
if (Interlocked.Exchange(ref this.fullIsLoading, 1) == 0) {
37+
this.loader?.EnqueueFullSizeRead(this, this.setFrom);
38+
}
39+
return this.ThumbImage;
40+
}
2041
}
2142
set {
22-
SetValue(FullImageProperty, value);
43+
if (value == null) {
44+
if (Interlocked.Exchange(ref this.fullImageRef, null) != null) {
45+
this.PropertyChanged?.Invoke(this,
46+
new PropertyChangedEventArgs(nameof(FullImage)));
47+
}
48+
return;
49+
} else if (this.fullImageRef == null) {
50+
this.fullImageRef = new WeakReference<BitmapImage>(value);
51+
} else {
52+
this.fullImageRef.SetTarget(value);
53+
}
54+
fullIsLoading = 0;
55+
Thread.MemoryBarrier();
56+
this.PropertyChanged?.Invoke(this,
57+
new PropertyChangedEventArgs(nameof(FullImage)));
58+
MemoryCache.Default.Set(
59+
this.FileName,
60+
value,
61+
cachePolicy);
2362
}
2463
}
25-
public static readonly DependencyProperty FullImageProperty =
26-
DependencyProperty.Register(nameof(FullImage),
27-
typeof(BitmapImage), typeof(Photo));
2864

2965
public BitmapImage ThumbImage {
3066
get {
3167
return (BitmapImage)GetValue(ThumbImageProperty);
3268
}
3369
set {
3470
SetValue(ThumbImageProperty, value);
71+
this.PropertyChanged?.Invoke(this,
72+
new PropertyChangedEventArgs(nameof(FullImage)));
3573
}
3674
}
3775
public static readonly DependencyProperty ThumbImageProperty =
@@ -58,11 +96,13 @@ internal class Metadata {
5896
}
5997

6098
private Metadata setFrom = null;
99+
internal ImageLoadManager loader = null;
61100
private bool setting = true;
62101

63102
internal void Set(Metadata from) {
64103
this.setting = true;
65104
this.setFrom = from;
105+
Thread.MemoryBarrier();
66106
if (from.Title != null) {
67107
this.Title = from.Title;
68108
} else {
@@ -236,6 +276,7 @@ public void Dispose() {
236276
Thread.MemoryBarrier();
237277
this.FullImage = null;
238278
this.ThumbImage = null;
279+
MemoryCache.Default.Remove(this.FileName);
239280
ThreadPool.QueueUserWorkItem(async _ => {
240281
bool locked = false;
241282
try {

PhotoTagger.Imaging/PhotoTagger.Imaging.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
<Reference Include="System" />
4141
<Reference Include="System.Core" />
4242
<Reference Include="System.Numerics" />
43+
<Reference Include="System.Runtime.Caching" />
4344
<Reference Include="WindowsBase" />
4445
</ItemGroup>
4546
<ItemGroup>

0 commit comments

Comments
 (0)