在将我们庞大的分布式系统部署到我们的客户之后,我们遇到了意外错误。在调查期间,我们将导致错误的组件替换为我们添加了一些诊断代码的组件。我们使用的DLL是在调试模式下构建的。突然一切都行了!
使用发行版本(使用诊断代码)替换调试dll会使其再次崩溃。
我们的代码中没有预编译器指令,条件调试属性等。在两个不同的安装站点中发现了这个问题,而在其他几个站点中它可以正常工作。
(该项目混合使用C#和VB.NET,麻烦组件是VB.NET ..如果这有什么不同的话)
所以问题是: 你在这样的情况下做了什么?原因可能是什么? 欢迎任何有关调试此问题的建议。
答案 0 :(得分:12)
对于原因......好吧,一些症状的暗示会有所帮助。一种可能性是你有一个像Debug.WriteLine
这样的方法的代码有副作用(即使其工作)。除非您定义了正确的符号,否则不会编译对标有[Conditional(...)]
的方法的调用 - 因此任何标记为[Conditional("DEBUG")]
的内容都将被静默删除。
它也可能是一个编译器错误,但这有点不太可能(但并非不可能)。
症状是什么?它是如何破裂的?
作为上述例子:
static string Bar { get; set; }
static void Main()
{
Bar = "I'm broken";
Debug.WriteLine(Foo());
Console.WriteLine(Bar);
}
// note Foo only called in DEBUG builds
static string Foo()
{
Bar = "I'm working";
return "mwahahah";
}
在DEBUG模式下编辑它打印“我正在工作”;在RELEASE模式下编译它打印“我坏了”。这听起来有点类似吗?检查您是否直接使用具有副作用的东西调用任何调试方法 。在大多数情况下,您可以通过间接修复:
string foo = Foo();
Debug.WriteLine(foo);
现在可以在任一模式下调用它。
答案 1 :(得分:5)
您可以尝试在Build Settings中关闭Optimize Code。你得到的实际错误是什么。
您可以做的另一件事是在发布模式下编译,但启用#Debug条件。如果你使用Diagnostics.Debug及其中的代码影响你的应用程序,这将处理这种情况。
答案 2 :(得分:4)
Debug.Assert(ImportantMethod());
答案 3 :(得分:4)
您是否尝试过包含调试文件? (pdbs)
如果您执行项目设置然后编译'选项卡'在顶部附近的下拉列表中选择您的发布版本,然后选择底部附近的高级编译选项,请确保将其设置为创建FULL调试信息,然后重新部署,您现在应该获得有关崩溃原因的更详细信息。
答案 4 :(得分:4)
我已经看到了导致Debug和Release版本之间出现问题的时序。通常,Debug构建比Release构建运行得慢。您可能想要检查代码的时间关键部分。
答案 5 :(得分:3)
如果你没有使用单线程代码,那么你可能会遇到某种竞争条件。例如,如果程序的某些部分需要在其他部分可以访问之前执行某些操作,那么它可能会在发布模式下失败,因为代码的访问过早。我们曾经遇到类似的问题,手机的某些代码在模拟器中运行良好,但在手机上运行较慢,情况根本不同。
答案 6 :(得分:3)
包含为多个客户端应用程序提供的WCF客户端的C#DLL遇到相同的问题。
发现C#客户端库中有一种方法可以访问StackTrace进行日志记录,而在调试中进行编译时会有所不同。
StackTrace stackTrace = new StackTrace();
MethodBase methodBase = stackTrace.GetFrame(2).GetMethod();
GetFrame(2)
在发行版中不存在。有关此信息的更多信息,请参见:StackTrace class methods not working in release mode
有趣的是,一个VB.NET客户端受到影响,而在另一个C#.NET客户端中,它正常工作。
希望有帮助。
答案 7 :(得分:1)
我终于遇到了一个问题,终结器比预期的更快,因为我没有完全理解终结器,垃圾收集器之间的相互作用,以及当一个本地对象被认为是可收集的时(提示:它不是在关闭时)块的大括号)。如果您的代码使用终结器,您可能希望查看GC.KeepAlive()。在以下块中:
void MyFunction()
{
Foo f = new Foo();
SomeFunction(f.SomeProp);
}
在f
甚至运行之前, SomeFunction()
才有资格完成定稿!如果终结者做了类似处理任何SomeProp
手的事情,你可能会遇到麻烦。在致电GC.KeepAlive(f)
后向SomeFunction
添加来电可确保f
在调用KeepAlive()
之后无法完成最终确定。
编辑:毕竟,我忘了指出在发布模式下运行时这个问题更加明显。我不知道Debug构建是否为函数末尾的本地函数放置了隐式KeepAlive以获得调试器的好处,或者垃圾收集是否更具侵略性,或者是什么,但Release模式在我的情况下极大地加剧了这个问题。 / p>
答案 8 :(得分:1)
确保应用程序正在正确的平台目标下构建。这可能是一个问题,尤其是在提供或使用DLL时。查看"项目 - >属性"并选择" Build"标签。 Platform目标选项允许您在Any CPU(默认),x86或x64之间进行选择。
答案 9 :(得分:1)
首先抱歉我的英语。我知道这篇文章已经过时了,但我遇到了同样的问题,我发现在调试模式下,构建是针对 32位操作系统,而发布模式是针对 64位强>默认情况下。这使得用于32位的dll在发布时不起作用。如果您转到项目属性 - >构建您可以选择您想要的架构。这适合我。 再见。
答案 10 :(得分:0)
你可能知道这个,但是, 变量有时在调试和发布版本中初始化不同。 例如。 我认为变量是在VC6调试版本中自动初始化的,如果你没有初始化某些东西,这可以隐藏问题。我还认为调试阵列可能会使用sentry字节来尝试指示溢出。这也会导致不同的行为。
答案 11 :(得分:0)
我有类似的问题。我的情况是这样的: 我在类库A中定义了一些反射函数。然后我定义了一个WPF用户控件库B,它使用库A中的函数。然后我编写了一个应用程序,它使用库B中的用户控件和库A中的函数。当我使用了库B的调试版,它工作正常。但是当我使用库B的发行版时,反射函数不起作用。我还在库A中定义了其他函数。似乎只有反射函数会引起麻烦。我无法弄清楚原因。最后,我放弃并将反射函数从库A移动到库B.并且它有效。
答案 12 :(得分:0)
你解决了问题吗?
我和你有同样的问题
如果我在调试中编译dll,一切正常
如果我在发布中编译,我会得到一个空引用异常
但是如果我在某些方法调用中包含一些像上面那样的行,那么即使在释放模式下异常也会消失:
System.Diagnostics.EventLog.WriteEntry(“blablabla”,“blablabla”)
希望对你有帮助。
答案 13 :(得分:0)
在我的情况下,我的DLL消费者项目(在VS中)具有x64配置,但解决方案是在任何CPU中。 出于某种原因,在运行应用程序时,这并未与我的x64 DLL挂钩。 我将应用程序配置为x64显式平台,一切正常。
答案 14 :(得分:0)
这可能与原始问题无关,但对于运行使用以下内容的应用程序的任何人
var isThisMyAssembly = System.Reflection.Assembly.GetCallingAssembly();
该调用有可能在运行时内联到另一个程序集中的方法中,从而获得意外的输出(如MSDN documentation中所述)。
为避免这种情况,您可以将MethodImplAttribute
应用于您的方法:
[MethodImpl(MethodImplOptions.NoInlining)]
void DoSomeThings()
{
var isThisMyAssembly = System.Reflection.Assembly.GetCallingAssembly();
//do stuff
}
,或者您也可以改用Assembly.GetExecutingAssembly()
。