class Program : CriticalFinalizerObject
{
static void Main(string[] args)
{
Program p = new Program();
TextWriterTraceListener listener = new TextWriterTraceListener(@"C:\trace.txt");
Trace.Listeners.Clear(); // Remove default trace listener
Trace.Listeners.Add(listener);
Trace.WriteLine("First Trace"); // Generate some trace messages
Trace.WriteLine("Perhaps last Trace.");
}
~Program()
{
Trace.Close();
}
}
Run Code Online (Sandbox Code Playgroud)
我得到文件大小= 0
finilizer 应该执行因为我来自CriticalFinalizerObject
我不想在Finalizer中使用Trace.Close().
@eric利珀特后答复:香港专业教育学院重新编辑的代码,试图把它匹配:约束的执行区域 (但仍然没有成功)
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
class Program : CriticalFinalizerObject
{
static void Main(string[] args)
{
RuntimeHelpers.PrepareConstrainedRegions();
try
{
}
catch (Exception e)
{
}
finally
{
Program …Run Code Online (Sandbox Code Playgroud) 换一种说法,
class Foo
{
object obj;
Foo() { obj = new object(); }
~Foo() { obj.ToString(); /* NullReferenceException? */ }
}
Run Code Online (Sandbox Code Playgroud) 根据文档(MSDN:链接),很明显在实现终结器时应该使用IDisposable模式.
但是,如果实现IDisposable(以便提供处理对象的确定性方法),您是否需要实现终结器?并且您没有任何非托管资源来清理?
在我看来,如果类只有托管资源,如果你不调用Dispose,那么托管资源将自动被GC清理,因此不需要实现终结器.我错了吗?
另外,如果我使用我的Dispose方法清理事件处理程序,该怎么办?由于Dispose不会自动被GC调用,我应该实现Finalizer,以确保事件处理程序无线连接吗?
我有一个应用程序,从单词go经历缓慢的内存泄漏.
使用ANTS Memory Profiler我可以看到所有泄漏的内存都由终结器队列的GC根保存.
我怀疑可能发生的事情是终结器已经死锁,等待锁定变为可用.
我们的类都没有实现显式终结器,我们通常会避免使用它们,这使我认为锁可能与系统或库类有关.
我曾经看过SOS.dll终结器队列的内容,如果我正确解释它然后它报告第一个项目是一个实例System.Threading.Thread 但是我不确定队列的头部是否实际代表当前正在处理的对象或下一个待处理的对象.
更新
终结器线程的堆栈如下所示:
ntdll.dll!_ZwWaitForSingleObject@12() + 0x15 bytes
ntdll.dll!_ZwWaitForSingleObject@12() + 0x15 bytes
user32.dll!_NtUserPostMessage@16() + 0x15 bytes
kernel32.dll!_WaitForSingleObjectExImplementation@12() + 0x43 bytes
kernel32.dll!_WaitForSingleObject@8() + 0x12 bytes
ole32.dll!GetToSTA() + 0x72 bytes
ole32.dll!CRpcChannelBuffer::SwitchAptAndDispatchCall() - 0x1939 bytes
ole32.dll!CRpcChannelBuffer::SendReceive2() + 0xa6 bytes
ole32.dll!CAptRpcChnl::SendReceive() + 0x5b7 bytes
ole32.dll!CCtxComChnl::SendReceive() - 0x14b97 bytes
ole32.dll!NdrExtpProxySendReceive() + 0x43 bytes
rpcrt4.dll!@NdrpProxySendReceive@4() + 0xe bytes
rpcrt4.dll!_NdrClientCall2() + 0x144 bytes
ole32.dll!_ObjectStublessClient@8() + 0x7a bytes
ole32.dll!_ObjectStubless@0() + 0xf bytes
ole32.dll!CObjectContext::InternalContextCallback() …Run Code Online (Sandbox Code Playgroud) 请考虑以下代码:
using System;
namespace memoryEater
{
internal class Program
{
private static void Main(string[] args)
{
Console.WriteLine("alloc 1");
var big1 = new BigObject();
Console.WriteLine("alloc 2");
var big2 = new BigObject();
Console.WriteLine("null 1");
big1 = null;
//GC.Collect();
Console.WriteLine("alloc3");
big1 = new BigObject();
Console.WriteLine("done");
Console.Read();
}
}
public class BigObject
{
private const uint OneMeg = 1024 * 1024;
private static int _idCnt;
private readonly int _myId;
private byte[][] _bigArray;
public BigObject()
{
_myId = _idCnt++;
Console.WriteLine("BigObject {0} creating... ", _myId);
_bigArray …Run Code Online (Sandbox Code Playgroud) 我一直认为这个问题的答案是否定的,但我找不到任何来源说明这一点.在我下面的课程中,我可以访问C终结器中实例的(托管)字段/属性,即在ReleaseUnmanaged()?有什么限制,如果有的话?GC或者终结是否会将这些成员设置为空?
我唯一能找到的是终结队列中的东西可以按任意顺序完成.所以在这种情况下,由于建议类型应该允许用户Dispose()多次调用,为什么推荐的模式会打扰disposing boolean?如果我的终结者打电话Dispose(true)而不是Dispose(false)?
public class C : IDisposable
{
private void ReleaseUnmanaged() { }
private void ReleaseOtherDisposables() { }
protected virtual void Dispose(bool disposing)
{
ReleaseUnmanaged();
if (disposing)
{
ReleaseOtherDisposables();
}
}
~ C()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
Run Code Online (Sandbox Code Playgroud) .NET有一个名为的函数GC.KeepAlive(Object).其唯一目的是确保引用对象的生命周期持续到代码流到达调用.
除非有人与本机代码进行互操作,否则通常不需要这样做.
我有一种情况,我有一个通过JNI访问的C++对象的图形,其中某些根对象需要保持活动以保持孩子们活着.根对象和子对象都在JVM域中具有镜像.但是,如果在C++端(通过SWIG生成的终结器)收集和释放根对象,则子对象将变为无效,因为它们的C++后备对象将被释放.
这可以通过确保根对象图的局部变量的生命周期超过上次使用子对象来解决.所以我需要一个惯用的函数,它不会对对象做任何事情,但不会被优化掉或移动(例如从循环中提升).这就是GC.KeepAlive(Object).NET中的功能.
Java中的近似等价物是什么?
PS:一些可能的说明性代码:
class Parent {
long ptr;
void finalize() { free(ptr); }
Child getChild() { return new Child(expensive_operation(ptr)); }
}
class Child {
long ptr;
void doStuff() { do_stuff(ptr); }
}
// BAD CODE with potential for SIGSEGV
for (Parent p : getParents()) {
p.getChild().doStuff();
}
Run Code Online (Sandbox Code Playgroud)
麻烦的是,在doStuff执行时,GC释放Parent p将释放为Child分配的内存.已经观察到GC在实践中这样做.GC.KeepAlive可用的潜在修复:
// BAD CODE with potential for SIGSEGV
for (Parent p : getParents()) {
p.getChild().doStuff();
GC.KeepAlive(p);
}
Run Code Online (Sandbox Code Playgroud)
我可以例如调用toStringp,但我不会对其输出做任何事情.我可以暂时将p戳到一个数组中,但我怎么知道JVM不会丢弃商店?等等.
.net java java-native-interface garbage-collection finalizer
我看到我维护的一些代码存在问题.下面的代码有一个private static SHA1成员(这是一个IDisposable但是因为它static,它应该永远不会最终确定).但是,在压力下,此代码会抛出一个异常,表明它已被关闭:
Caught exception. Safe handle has been closed"
Stack trace: Call stack where exception was thrown
at System.Runtime.InteropServices.SafeHandle.DangerousAddRef(Boolean& success)
at System.Security.Cryptography.Utils.HashData(SafeHashHandle hHash, Byte[] data, Int32 cbData, Int32 ibStart, Int32 cbSize)
at System.Security.Cryptography.Utils.HashData(SafeHashHandle hHash, Byte[] data, Int32 ibStart, Int32 cbSize)
at System.Security.Cryptography.HashAlgorithm.ComputeHash(Byte[] buffer)
Run Code Online (Sandbox Code Playgroud)
有问题的代码是:
internal class TokenCache
{
private static SHA1 _sha1 = SHA1.Create();
private string ComputeHash(string password)
{
byte[] passwordBytes = UTF8Encoding.UTF8.GetBytes(password);
return UTF8Encoding.UTF8.GetString(_sha1.ComputeHash(passwordBytes));
}
Run Code Online (Sandbox Code Playgroud)
我的问题显然是可能导致这个问题的原因.呼叫是否可以SHA1.Create静默失败(有多少加密资源可用)?这可能是因为appdomain失败了吗?
还有其他理论吗?
我注意到使用VS 2013在.Net 4.0中的32位和64位下编译控制台应用程序时GC的行为不一致.
请考虑以下代码:
class Test
{
public static bool finalized = false;
~Test()
{
finalized = true;
}
}
Run Code Online (Sandbox Code Playgroud)
在Main()......
var t = new Test();
t = null;
GC.Collect();
GC.WaitForPendingFinalizers();
if (!Test.finalized)
throw new Exception("oops!");
Run Code Online (Sandbox Code Playgroud)
在64位(调试)模式下运行时,每次都可以正常工作; 但是,在32位模式下运行我无法强制收集此对象(即使我创建了更多对象并等待一段时间,我已经尝试过).
有没有人对这是为什么有任何想法?在尝试调试一些必须处理为32位版本的程序集释放非托管代理数据的代码时,这会给我带来麻烦.在32位模式下有很多对象只是坐在那里很久以后(在64位中不是这样).
我正在尝试在32位模式下调试某些东西,但终结器不会被调用(至少不是强制调用).对象只是坐在那里永远不会被收集(我可以看到所有弱引用仍然有一个值).在64位模式下,所有弱引用都按预期清除,并且所有终结器都被调用.
注意:虽然上面的代码规模非常小,但我注意到在32位模式下,GC中有更多的对象,直到稍后创建更多对象(即使调用"Collect"和"WaitForPendingFinalizers").在64位模式下绝不是这种情况.我有一个用户想知道为什么这么多对象没有被收集,这导致我调查,我发现一切似乎在64位模式比32更好.只是试图理解为什么.
编辑:这是更好的代码来显示差异:
class Program
{
class Test
{
public static bool Finalized = false;
public int ID;
public Test(int id)
{
ID = id;
}
~Test()
{ // <= Put breakpoint here
Finalized = …Run Code Online (Sandbox Code Playgroud) finalizer ×10
c# ×7
.net ×6
dispose ×3
idisposable ×2
.net-4.0 ×1
clr ×1
destructor ×1
java ×1
sha ×1