【发布时间】:2011-01-02 14:55:03
【问题描述】:
我有这个问题。我使用 MVVM 架构开发 WPF 应用程序。作为 MVVM 框架,我使用 Caliburn.Micro,在服务注入方面我使用 MEF。
在视图模型类中,我使用 Dispatcher Timer,它每 3 秒调用一次服务方法。此服务方法在服务器上发送 POST 请求并使用 JSON.NET 解析 HTML 响应/反序列化 JSON 字符串。
此方法返回可观察字典,类型为:字符串,朋友。
Friend 类只包含字符串属性和一张图片作为 BitmapImage 类型。
服务方法如下:
public MyObservableDictionary<string, Friend> LoadFriends(Account account)
{
var friends = new MyObservableDictionary<string, Friend>();
var sortedFriends = new MyObservableDictionary<string, Friend>();
const string allData = "&allData=1";
var htmlStringResult = new StringBuilder();
htmlStringResult = "GET HTML RESPOSE"
if (htmlStringResult.Length > 3 && htmlStringResult.ToString() != "false")
{
try
{
var jsonString = new StringBuilder();
jsonString.Append(htmlStringResult.Replace(@"s_", "m_"));
var friendsAsStringArray = JsonConvert.DeserializeObject<MyObservableDictionary<string, string[]>>(jsonString.ToString());
foreach (var friend in friendsAsStringArray)
{
var item = new KeyValuePair<string, Friend>(friend.Key, new Friend
{
IdUser = friend.Value[0],
Nick = friend.Value[1],
SefNick = friend.Value[1],
Status = int.Parse(friend.Value[2]),
Photo = friend.Value[3],
Sex = int.Parse(friend.Value[4]),
IsFriend = Convert.ToBoolean(int.Parse(friend.Value[5]) * -1)
});
friends.Add(item);
}
//sort item in dictionary A-Z
var query = friends.OrderByDescending(f => f.Value.Status).ThenBy(f => f.Value.Nick);
foreach (var keyValuePair in query)
{
sortedFriends.Add(keyValuePair.Key, keyValuePair.Value);
}
//CLEAN OLD DATA
friends.Clear();
}
catch (Exception exception)
{
throw exception;
}
return sortedFriends;
}
return new MyObservableDictionary<string, Friend>();
}
在视图模型类中,我在列表框上绑定了可观察字典。在这个类中,我每 3 秒调用一次计时器服务方法 LoadFriend。
我在可观察字典中返回新数据,并使用这些数据刷新绑定在列表框上的字典。
这是视图模型类:
[Export(typeof(IMessengerViewModel))]
public class MessengerViewModel : Screen, IViewModelIdentity,
IMessengerViewModel, IHandle<Rp>, IHandle<string>
{
private IPokecService _service;
private MyObservableDictionary<string, Friend> _friends;
private MyObservableDictionary<string, Friend> _freshFriends;
private DispatcherTimer _dispatcherTimer;
[ImportingConstructor]
public MessengerViewModel(IPokecService service)
{
_service = service;
_dispatcherTimer = new DispatcherTimer();
_dispatcherTimer.Tick += DispatcherTimer_Tick;
_dispatcherTimer.Interval = TimeSpan.FromSeconds(3);
_dispatcherTimer.Start();
}
#region Timer
/// <summary>
/// Refresh contact list, check for new messages
/// </summary>
/// <param name="sender"></param>
/// <param name="eventArgs"></param>
private void DispatcherTimer_Tick(object sender, EventArgs eventArgs)
{
//retrieve new data from server
_freshFriends = _service.LoadFriends(Account);
_friends.Clear();
//refresh dictionary
foreach (var freshFriend in _freshFriends)
{
_friends.Add(freshFriend);
}
}
#endregion
}
我做一个简单的测试:
- 使用计时器运行应用程序
- 在没有计时器的情况下运行应用程序
- 带有计时器,但逻辑为空 timer_tick 方法
我在任务管理器和 ANTS 内存分析器中检查值,这里是值:
任务管理器进程:
- 带计时器的应用程序
- 开始后:40,133K
- 5 分钟后:70,261K
- 10 分钟后:74,288K
- 没有计时器的应用程序
- 开始后:37,488K
- 5 分钟后:37,412K
- 10 分钟后:37,760K
- 具有计时器但逻辑为空的应用
- 开始后:37,474K
- 5 分钟后:37,340K
- 10 分钟后:37,476k
ANTS 内存分析器 - 私有字节
- 带计时器的应用程序
- 启动后:73,132MB
- 5 分钟后:97,72MB
- 10 分钟后:100,12MB
- 没有计时器的应用程序
- 启动后:67,24MB
- 5 分钟后:66.21MB
- 10 分钟后:66,21MB
- 具有计时器但逻辑为空的应用
- 启动后:67.3MB
- 5 分钟后:66.32MB
- 10 分钟后:66,41MB
我不知道这个值是否正常。也许我的应用程序有内存泄漏。
我的第一个想法是在 Friend 类中检查图像,但图像存储在 BitmapImage 类中。这个类没有实现接口IDisposable,所以我不能对字典中的旧项调用Dispose方法。
私有字节的最大值为 124,12 MB,我认为这已经足够了。
我从不处理 .NET 中的内存使用情况,我不知道会出现什么问题。
感谢您的帮助,如果有人向我解释这个问题,我将非常感激他/她。
我想调用我的计时器垃圾收集器,但我认为这是一个很好的主意。
一张图片的大小为 5-10kB。在字典中大约有 20-30 项。
我从网上下载图片,图片 uri 是 URL。
public BitmapImage ProfilePhoto ...{ get; set; }
private BitmapImage CreateProfilePhoto()
{
var img = new BitmapImage();
img.BeginInit();
img.UriSource = Photo == "0" ? DefaultPhoto.GetDefaultPhoto(Sex) : new Uri(PhotoURL, UriKind.Absolute);
img.EndInit();
return img;
}
....
ProfilePhoto = CreateProfilePhoto();
【问题讨论】:
-
如果你已经有一个内存分析器,为什么不使用它来查看“泄漏”了什么?使用 ANTS 拍摄快照并查看创建了哪些对象,但未销毁哪些对象并得出结论。
-
我试了一下,但我找不到内存泄漏.. :(
标签: .net memory-leaks garbage-collection timer memory-management