2013-05-22 30 views
4

我必須生成大的大圖像,像15000x3000。我用GDI +生成了這個圖像,類別爲Bitmap檢索可用的連續內存

當然,由於沒有更多的內存來實例化位圖,所以該代會不時失敗。我的目標是告訴我的用戶他們可以生成的圖像的最大尺寸。

的消息應該是這樣的:

您試圖生成大小15000x3000的圖像,但沒有足夠的內存。 可用的最大尺寸爲10000x3000或15000x1000。

的想法創建消息是類似的東西:

public bool CanCreateBitmap(Size size, out string message) 
{ 
    long availableMemory = this.GetAvailableContiguousMemory(); 
    long bytesRequiered = (long)size.Width * size.Height * 32; 

    if (availableMemory < bytesRequiered) 
    { 
     var sizeProposal1 = new Size(size.Width, (int)(availableMemory/(32 * size.Width))); 
     var sizeProposal2 = new Size((int)(availableMemory/(32 * size.Height)), size.Height); 

     message = string.Format("You tried to generate an image of size {0}, but there is not enough memory." 
       + Environment.NewLine + "The maximum size available is {1}, or {2}." 
       , size, sizeProposal1, sizeProposal2); 

     return false; 
    } 
    else 
    { 
     message = ""; 
     return true; 
    } 
} 

但我沒有代碼的功能GetAvailableContiguousMemory()

有沒有一種方法來檢索.Net中的連續內存?
我在問正確的問題以達到我的目標嗎?

+0

也許你可以把位圖創建代碼放在try/catch塊中,並處理內存不足異常(如果發生的話)? – dandan78

+0

這已經是主意了,但這裏的主要觀點也是向用戶提出一些建議。他們感到無聊,只能得到一個「無法創建位圖」的信息而沒有更多的信息。 –

回答

3

沒有這樣的功能,因爲問題「我可以分配多少內存」包含競爭條件。假設存在一個你需要的函數,並且你調用它並告訴你有大量的可用內存。您將這些信息傳達給用戶,用戶決定圖像的大小,然後實際分配圖像。但是另一些進程在此期間已經佔用了一半的可用內存,而現在您的調用因OutOfMemoryException而中斷。

在通過TCP/IP進行媒體流傳輸時存在類似的問題。您希望開始流式傳輸視頻,但它需要相當多的網絡帶寬,並且您希望確保此帶寬在幾分鐘後纔會提供,因爲啓動視頻流只是爲了適得其反播放達到視頻長度的三分之二時卡住。現在,通過在握手階段預留網絡資源解決了這個問題 - 即使您現在沒有使用帶寬(視頻流尚未開始)。

那麼,你可能會試圖用一些模糊的Windows API調用來實現類似的效果。嘗試從VirtualAlloc函數開始研究。但是,我不建議你走這條路,因爲即使你的應用程序運行良好,應用程序可能不穩定或不可靠,或影響系統上的其他進程。尤其是,這些Windows API本來就是用C++編寫的,而且你正在使用.NET中的託管堆 - 我還沒有嘗試過這種方法,並且無法預測結果(但是如果成功的話,希望能夠聽到你的結果! )。

你問的是設計決定。我還建議dandan78的方法 - 讓用戶選擇圖像大小,嘗試創建它,並在嘗試失敗時通知錯誤。用戶最終會習慣於他們的計算機能力,並且不會經常將系統超出極限。

編輯:還有一件事你應該記住:沒有「可用的連續內存」這樣的東西。操作系統借給你一頁虛擬內存。這些頁面在被引用時被加載到內存中。如果你需要大量的內存,你會得到一堆頁面,這些頁面將在虛擬內存空間中被賦予連續的地址,這就是你如何得到內存連續的印象。但是由於內存管理器僅返回託管堆上的第一個可用插槽,因此通常會由new語句返回非連續的內存位置。我知道這些筆記是關於這個問題的主題,但是在像這樣的情況下記住管理內存策略當然不會受到傷害。

+0

確實,即使該函數返回true,創建也可能失敗。但是我已經添加了一個try catch來創建實例。該功能只是爲了給用戶添加建議。 –

+0

我明白你需要什麼。還有一件事你應該記住:沒有「可用的連續記憶」這樣的事情。操作系統借給你一頁虛擬內存。這些頁面在被引用時被加載到內存中。如果你需要大量的內存,你會得到一堆頁面,這些頁面將在虛擬內存空間中被賦予連續的地址,這就是你如何得到內存連續的印象。擁有非連續內存的唯一方法是從先前分配的頁面中獲取大量內存,當您分配大量小對象時會觸擊您。 –

+0

@sysexpand:你的評論關於如何分配工作將是一個很好的補充你的答案。 –

3

這些類型的通知是實際上並沒有幫助用戶的創可貼。他們真的想要創造出這麼大的位圖,而任意小的一個並不是他們想要的。如果你想這樣做,那麼你需要調用VirtualQuery來遍歷虛擬地址空間並找到尚未映射的塊。

這些日子已經沒有任何意義,將項目的平臺目標設置更改爲AnyCPU,以便程序可以使用64位操作系統上可用的虛擬內存空間的gobs。