2017-05-10 26 views
0

假設您有一個.net對象bufferObject,它在內部使用某種非相當大小的非託管內存緩衝區。它的實現方式是在處置(或最終)時釋放分配的內存。如何使用C#將對象生命週期與另一個對象生存期綁定在一起#

然後,您創建一個不同的對象reusingBufferObject併爲其提供指向內部緩衝區bufferObject的指針。所以這兩個對象本身並不知道彼此的存在。

bufferObject如果超出範圍,並且設置/完成,內部緩衝器將被釋放並reusingBufferObject將訪問無效的內存。

當然,通過改變兩個對象的基礎分類的設計並且讓reusingBufferObject參考bufferObject可以避免整個問題。但是讓我們假設這兩個對象都是第三方類的實例,並且它們的設計不能改變。

一個例子就是使用一些圖像處理庫。內部圖像對象必須轉換爲Bitmap對象才能在屏幕上顯示它,但出於性能原因,圖像對象內部緩衝區必須由Bitmap對象重用,而不是僅複製到該對象。

是否有可能只reusingBufferObject後的bufferObject壽命綁的reusingBufferObject壽命,所以它得到符合垃圾收集呢,不用手動保持一生的軌跡?

編輯:

這裏一個簡單的例子來說明這個問題:

namespace Example 
{ 
    // Some third party class with no control over its design. 
    // The Data property is the pointer to an unmanaged memory 
    // buffer. 
    public class ThirdPartyImage : IDisposable 
    { 
     public int Width { get; } 
     public int Height { get; } 
     public int Stride { get; } 
     public PixelFormat Format { get; } 
     public IntPtr Data { get; } 

     public ThirdPartyImage(string filename); 
     public Dispose(); 
    } 

    public static class MyOwnExtensions 
    { 
     // Some method to reuse the internal memory buffer. 
     public static Bitmap ToBitmap(this ThirdPartyImage image) 
     { 
      return new Bitmap(image.Width, image.Height, image.Stride, image.Format, 
       image.Data); 
     } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      Bitmap bitmap = Foo(); 

      // ThirdPartyImage is not referenced anymore and the internal buffer (Data) 
      // will be freed when garbage collected. 

      Bar(bitmap); 
     } 

     private static Bitmap Foo() 
     { 
      ThirdPartyImage image = ThirdPartyImage("foo.bmp"); 
      Bitmap bitmap = image.ToBitmap(); 

      return bitmap; 
     } 

     private static void Bar(Bitmap bitmap) 
     { 
      // Do some Bitmap related work here. 
      // The buffer could already be freed though. 
     } 
    } 
} 

編輯:

我所尋找的是像一個垃圾收集方法,即可以讓你將一個對象的生命期限與另一個對象相連

或者某種當正在收集或獲得符合回收,這樣我就可以建立包括持有的強引用bufferObjectWeakReferencereusingBufferObject輔助對象一些自動化的機制reusingBufferObject/Bitmap通知。

手動跟蹤兩個實際上不再需要的對象(除了內部使用的緩衝區),例如引入一個包裝類,對我來說似乎過於複雜。

+0

它取決於'bufferObject'派生自哪個類。另外,你能否提供有關一般涉及的類型的更多細節? 'bufferObject'和'reusingBufferObject'類型的元數據視圖將非常有用。 –

+1

沒有更多細節,不可能回答這個問題。各種對象如何分配和銷燬的確切語義決定了這是否可以完成。 – xxbbcc

+1

即使在'reusingBufferObject'之前沒有收集'bufferObject',你打算如何防止'bufferObject.Dispose()'調用? –

回答

1

好吧,看起來ConditionalWeakTable<TKey, TValue>正在做我想做的。 通過稍微改變示例,它應該可以工作:

public static class MyOwnExtensions 
{ 
    private static readonly ConditionalWeakTable<Bitmap, ThirdPartyImage> 
     WeakBitmapImageTable = new ConditionalWeakTable<Bitmap, ThirdPartyImage>(); 

    public static Bitmap ToBitmap(this ThirdPartyImage image) 
    { 
     Bitmap bitmap = new Bitmap(image.Width, image.Height, image.Stride, image.Format, 
      image.Data); 
     WeakBitmapImageTable.Add(bitmap, image); 

     return bitmap; 
    } 
} 
1

創建該對象的任何人都有責任處置它們。如果您有objectAobjectA需要objectB但兩個對象都是由第三個對象objectC創建的,則objectC需要確保將它們兩者都處置。

這是最重要的一點要記住:創建者負責處置

這是一些IoC容器的最大問題之一:它們創造了一些東西,但當涉及到處置時,事情留給其他人處理,這使得事情變得非常棘手。

0

您的問題的第一部分是非常通用的,它不能按原樣回答。我的回答只是試圖回答你在問題中的具體代碼示例。

由於ThirdPartyImage實現了IDisposable,它的預期行爲是它保留該緩衝區,直到您調用Dispose()爲止。如果您不想複製圖像緩衝區,則必須在位圖的整個生命週期內保留對ThirdPartyImage的引用,否則當緩衝區被釋放並且位圖渲染失敗時,程序會在某個點崩潰。

您可以通過多種方式做到這一點 - 在使用ThirdPartyImage實例的全球地圖,通過位圖鍵控(這是很棘手,迅速成爲一個維護問題),或者你可以保持兩個對象(ThirdPartyImage和位圖)班級,你傳遞到每個地方(你可以)。這樣,當您準備好擺脫位圖時,您只需銷燬位圖對象,該對象將在位圖上然後在ThirdPartyImage上調用Dispose()

你可以嘗試想出一些方法來隱藏這種似乎自動化的結構中的這種設置,但最終一個對象到達另一個對象並將它們連接在一起。只有你知道何時可以安全地擺脫第一個對象,以便第二個對象也可以消失。