【发布时间】:2016-04-22 05:52:30
【问题描述】:
我有一个在 UI 中填充 1000 个 ComboBox 的类,代码是
namespace ActiveXMemory
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
PopulateControls();
}
public void PopulateControls() {
var newGrid = new Grid();
for (var i = 0; i < 1000; i++)
{
ComboBox newcombo = new ComboBox();
newGrid.Children.Add(newcombo);
}
this.Content = newGrid;
}
public bool OpenWindow(bool isRunning)
{
Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() =>
{
try
{
this.ShowDialog();
}
catch (Exception exp)
{
Console.WriteLine(exp.Message);
}
}));
return true;
}
public bool CloseWindow()
{
Dispatcher.Invoke(DispatcherPriority.Render, new Action(() =>
{
try
{
this.Close();
}
catch (Exception exp)
{
//Console.WriteLine(exp.Message);
}
}));
return true;
}
private void Window_Closed(object sender, EventArgs e)
{
var grid = Content as Grid;
var children = grid.Children;
while (children.Count > 0)
{
var child = children[0];
grid.Children.Remove(child);
child = null;
}
grid = null;
}
}
}
我为该类创建了一个 ActiveX 库,以便作为 ActiveX 访问,
namespace ActiveXLibrary
{
[ComVisible(true)]
[Guid("EF2EAD91-68A8-420D-B5C9-E30A6F510BDE")]
public interface IActiveXLib
{
[DispId(1)]
bool Initialize();
[DispId(2)]
bool CloseActiveX();
}
[ComVisible(true)]
[Guid("9DACD44F-0237-4F44-BCB9-0E6B729915D6"),
ClassInterface(ClassInterfaceType.None)]
[ProgId("Samp")]
public class ActiveXLib : IActiveXLib
{
MainWindow form;
Thread thr;
public bool Initialize()
{
int i = 0;
try
{
ThreadStart exeFunc = new ThreadStart(() =>
{
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Send, new Action(() =>
{
start();
}));
});
thr = new Thread(exeFunc);
thr.SetApartmentState(ApartmentState.STA);
thr.Start();
while (form == null)
{
i++;
//Console.WriteLine("form Null");
System.Threading.Thread.Sleep(1000);
if (i > 30)
break;
}
return true;
}
catch (Exception exp)
{
Console.WriteLine("[Initialize]" + exp.Message);
return false;
}
}
public bool CloseActiveX()
{
bool success = false;
try
{
success = form.CloseWindow();
form = null;
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
return success;
}
catch (Exception exp)
{
Console.WriteLine("[CloseActiveX]" + exp.Message);
return false;
}
}
private void start()
{
try
{
Console.WriteLine("start() - new MainWindow()");
form = new MainWindow();
Console.WriteLine("OpenWindow()");
form.OpenWindow(true);
}
catch (Exception exp)
{
MessageBox.Show(exp.Message + "\nPossible Reasons: " + exp.Source + "\n" + exp.InnerException, "Error");
}
}
}
}
然后我创建了一个演示项目
ActiveXLib activeXRef;
public MainWindow()
{
InitializeComponent();
}
private void startButton_Click(object sender, RoutedEventArgs e)
{
activeXRef = new ActiveXLib();
activeXRef.Initialize();
}
private void stopButton_Click(object sender, RoutedEventArgs e)
{
activeXRef.CloseActiveX();
GC.Collect();
}
这里的问题是每次我点击开始和停止按钮时,内存不断增加,应用程序第一次启动创建的内存(17MB)没有被释放,即使我删除了 ComboBoxes 并设置了网格内容为空。甚至 GC.Collect() 也没有效果,因为它只会将垃圾添加到队列中。有什么解决办法吗?
我也尝试过像link那样刷新内存,但即使这样,内存仍然保留。(因为我不确定当前进程的句柄是否来自演示项目/来自ActiveXMemory)
编辑
我加入了这条线
this.Dispatcher.Invoke(DispatcherPriority.Render, GCDelegate);
到 Window_Closed 事件
现在内存被清除了
但我现在面临的一个问题是,如果我尝试立即关闭(调用 CloseActiveX()),那么这不会发生。(即)
private void startButton_Click(object sender, RoutedEventArgs e)
{
activeXRef = new ActiveXLib();
activeXRef.Initialize();
activeXRef.CloseActiveX();
activeXRef = null;
GC.Collect();
}
上面的代码仍然有内存锁定,我不明白其中的区别,它只是另一个事件,有人对此有任何想法吗?
【问题讨论】:
-
在创建新对象之前,您是否尝试过执行 Marshal.ReleaseComObject(activeXRef)(当然,如果 activeXRef 不为空)。
-
我试过了,得到 ArgumentException "{"对象的类型必须是 __ComObject 或派生自 __ComObject。\r\n参数名称:o"}"
-
哦,是的,当然,抱歉,我忽略了您的代码,并认为 IActiveXLib 不是 .net。您可以使用 WinDbg 分析您的程序,这很容易理解发生了什么:blogs.msdn.microsoft.com/johan/2007/01/11/… 或 blogs.msdn.microsoft.com/tess/2008/02/20/…
-
我已经尝试了内存分析器,看到物理内存中仍然存在什么,但我不知道如何修复它
标签: c# wpf memory-leaks activex