2014-01-12 30 views
0

我在下面的編組情況中遇到了一個奇怪的問題。我有這樣一個對象:Marshalling包含MarshalByRefObj成員的Serializable數組

class CallbackWrapper : MarshalByRefObj 
{ 
    private Func<String, bool> _callback; 
    public CallbackWrapper(Func<String, bool> callback) 
    { 
     _callback = callback; 
    } 

    public bool Execute(String input) 
    { 
     return _callback(input); 
    } 
} 

[Serializable] 
class MyData 
{ 
    public CallbackWrapper Callback {get; private set;} 
    public UnfriendlyType Data {get; private set;} 
    public MyData(UnfriendlyType data, Func<String, bool> callback) 
    { 
     Data = data; 
     Callback = new CallbackWrapper(callback); 
    } 

    public MyData(MyData other, UnfriendlyType data) 
    { 
     Data = data; 
     Callback = other.Callback; 
    } 
} 

class MyModule : MarshalByRefObject 
{ 
    public MyData[] Data {get; private set;} 
    public MyModule() 
    { 
     Data = //etc 
    } 
} 

我有兩個appdomains,我將其稱爲Primary和ModuleDomain。我通過調用ModuleDomain.DoCallback(MethodWhichInstantiatesTheMyModule)在ModuleDomain中創建MyModule,該方法創建MyModule對象並通過SetData爲該域存儲該對象。主域然後檢索這個句柄,展開它,並在將代理註冊到ISponsor之後存儲該代理。這部分工作。一旦做到這一點,我觸發事件爲MyModule的,以表明新的數據是可用的(這發生在主AppDomain中):

HandleNewData(this, new NewDataAvailableEventArgs(myModuleProxy)); 

[Serializable] 
class NewDataAvailableEventArgs : EventArgs 
{ 
    public MyModule Module {get; private set;} 
    public NewDataAvailableEventArgs(MyModule module) 
    { 
     Module = module; 
    } 
} 

這在下面的方法結束了:

void ProcessNewData(object sender, NewDataAvailableEventArgs e) 
{ 
    var localData= new List<MyData>(); 
    var originals = e.Module.Data; // ***** This is where leases get constructed and destructed ***** 
    // Manually mess with the UnfriendlyType member of each element in originals (this is unrelated, but is why we have to do this copy construction in the Primary AppDomain). 
    localData.AddRange(from data in originals let originalData = originals[mappingFunc(data)] select new MyData(originalData, data)); 
    // Do more processing, add a sponsor to each of MyData.Callback, etc. 
} 

這裏是問題出現的地方。我將這些MyData對象與MyModule的關聯存儲在本地。稍後,我使用回調。這個想法是,CallbackWrapper將確保回調在ModuleDomain中執行,而不是在Primary中執行。這個工作五分鐘,但五分鐘後,CallbackWrapper對象被斷開連接並引發異常。這很奇怪,因爲我明確地註冊了每個MyData的贊助商。當我重寫了CallbackWrapper租賃代碼,我可以看到正在發生的事情:

class TrackingLease : ILease 
{ 
    private static uint LeaseIdCurrent = 0; 
    private uint LeaseId; 
    private ILease _baseLease; 
    public TrackingLease(ILease lease) 
    { 
     _baseLease = lease; 
     LeaseId = LeaseIdCurrent++; 
     Console.WriteLine("TrackingLease {0} constructed.\n", LeaseId); 
    } 
    ~TrackingLease() 
    { 
     Console.WriteLine("TrackingLease {0} destructed.\n", LeaseId); 
    } 
    // etc 
} 

當然,我重寫CallbackWrapper的InitializeLifetimeService包裝base.InitializeLifetimeService這個新TrackingLease。我所看到的是:每個CallbackWrapper都有一個構造和破壞,它發生在上面的標記行。問題在於破壞似乎幾乎立即發生;租約顯然是從垃圾收集器中立即收集垃圾(我可以看到TrackingLease析構函數在GCFinalizer線程上觸發,並且時間不確定)。

我認爲應該發生的是,在標記的行,我得到一個新的MyData對象按值編組。它應該包含對ModuleDomain中的CallbackWrapper的引用。當我構造新的MyData對象時,他們應該複製這個引用。如果我將贊助商附加到MyDataCopy.Callback引用,它應該避免被GC'd,這應該讓我在將來調用它。這不是正在發生的事情,但我不確定我做了什麼來彌補它。任何見解都會非常有幫助。

是否有任何其他信息可以幫助我回答這個問題?

+0

我覺得你邁德特包含代理CallbackWrapper,不整理在實際CallbackWrapper的參考。你可以使用'System.Runtime.Remoting.RemotingService.IsTransparentProxy(originals [0] .Callback)'檢查。 – th1rdey3

+0

這返回'真'。這是一個MarshalByRefObject - 它不應該作爲參考回來嗎?我如何影響這個?目標是讓回調在ModuleDomain中執行。 – Octavianus

回答

0

嘗試添加下列到CallbackWrapper

public override object InitializeLifetimeService() 
{ 
    return null; 
} 
+0

這些回調可以在運行時更新,因此不適合退出內存管理。這樣做的確會導致這種行爲沒有表現出來,但我的理解是它實際上只是泄露了CallbackWrapper,這實際上並不是一種選擇,因爲在應用程序的整個生命週期中可以有任意數量的它們。 – Octavianus