似乎微软试图将报告放入自己独立的内存空间中,以解决所有内存泄漏问题而不是解决问题。在这样做的时候,他们引入了一些硬性崩溃,并最终导致更多的内存泄漏无论如何。他们似乎缓存了报告定义,但从不使用它并从不清理它,并且每个新报告都会创建一个新的报告定义,占用越来越多的内存。
我玩弄同样的事情:使用一个单独的应用程序域并编组报告。我认为这是一个糟糕的解决方案,并且很快就会搞得一塌糊涂。
我所做的是相似的:将您的程序的报告部分分成它自己的单独的报告程序。无论如何,这是组织代码的好方法。
棘手的部分是将信息传递给单独的程序。使用Process
类启动报告程序的新实例,并在命令行上传递它需要的所有参数。第一个参数应该是一个枚举或类似的值,表示应该打印的报告。我给这家在主程序代码看起来是这样的:
const string sReportsProgram = "SomethingReports.exe";
public static void RunReport1(DateTime pDate, int pSomeID, int pSomeOtherID) {
RunWithArgs(ReportType.Report1, pDate, pSomeID, pSomeOtherID);
}
public static void RunReport2(int pSomeID) {
RunWithArgs(ReportType.Report2, pSomeID);
}
// TODO: currently no support for quoted args
static void RunWithArgs(params object[] pArgs) {
// .Join here is my own extension method which calls string.Join
RunWithArgs(pArgs.Select(arg => arg.ToString()).Join(" "));
}
static void RunWithArgs(string pArgs) {
Console.WriteLine("Running Report Program: {0} {1}", sReportsProgram, pArgs);
var process = new Process();
process.StartInfo.FileName = sReportsProgram;
process.StartInfo.Arguments = pArgs;
process.Start();
}
而且报告程序看起来像:
[STAThread]
static void Main(string[] pArgs) {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var reportType = (ReportType)Enum.Parse(typeof(ReportType), pArgs[0]);
using (var reportForm = GetReportForm(reportType, pArgs))
Application.Run(reportForm);
}
static Form GetReportForm(ReportType pReportType, string[] pArgs) {
switch (pReportType) {
case ReportType.Report1: return GetReport1Form(pArgs);
case ReportType.Report2: return GetReport2Form(pArgs);
default: throw new ArgumentOutOfRangeException("pReportType", pReportType, null);
}
}
你GetReportForm
方法应该拉报表定义,利用相关的参数,以获得数据集,将数据和任何其他参数传递给报表,然后将报表放置在表单的报表查看器中,并返回对表单的引用。请注意,可以提取这个过程的大部分内容,以便基本上可以说'使用这些数据和这些参数为这个汇编的报告提供一个表单'。
另请注意,这两个程序都必须能够看到与此项目相关的数据类型,因此希望您已将数据类提取到它们自己的库中,这两个程序都可以共享引用。在主程序中没有所有的数据类,因为在主程序和报表程序之间会有一个循环依赖关系。
不要过多地与参数做它,要么。在报告程序中查询您需要的任何数据库;不要传递大量的对象(这可能不会起作用)。你应该传递简单的东西,如数据库ID字段,日期范围等。如果你有特别复杂的参数,你可能需要将UI的那部分推到报表程序中,而不是在命令行上将它们作为参数传递。
您还可以在主程序中添加对报告程序的引用,生成的.exe和任何相关的.dll文件将被复制到相同的输出文件夹中。然后,您可以运行它而不指定路径,只使用可执行文件名(例如:“SomethingReports.exe”)。您还可以从主程序中删除报告dll。
与此相关的一个问题是,如果您从未实际发布过报告程序,您将收到明显错误。只是虚拟发布一次,生成一个清单,然后它将工作。
一旦你有这个工作,在打印报告时看到你的常规程序的内存保持不变是非常好的。报告程序出现了,占用了比主程序更多的内存,然后消失,完全清除了主程序占用的内存。
另一个问题可能是每个报表实例现在占用比以前更多的内存,因为它们现在是完全独立的程序。如果用户打印大量报告并且从不关闭它们,则会非常快地耗尽大量内存。但我认为这还是好得多,因为只要关闭报告就可以轻松回收记忆。
这也使得您的报告独立于您的主程序。即使在关闭主程序后,它们也可以保持打开状态,并且您可以手动从命令行生成它们,也可以从其他源生成它们。
只需双重检查:_only_ .NET框架已更改。还是你从32位机器转到64位?你是否从DEP转到非DEP?你是否从PAE转到非PAE?你从ngen去JIT吗?只是提示触发更多信息 – sehe 2011-06-02 22:07:11
这里没有足够的信息甚至冒险猜测。你偶然使用'BlockingCollection'或'ConcurrentQueue'类吗? 'ConcurrentQueue'有内存泄漏,这可能是一个问题。 – 2011-06-02 22:08:54
ConcurrentQueue在.NET 3.5中不存在,所以这不成问题。 – phoog 2011-06-02 22:11:29