2016-07-18 5 views
-2

私はいくつかの研究を行っています。プロセスがどのように動作するかを見るために単純なメモリマネージャシステムを実装しましたが、私はMemoryHelperクラスの無料メソッドと "Marshal" FreeHGlobal "メモリを解放した後でさえ、可能な限りデータにアクセスできるように、メモリ内の空きを実現しません。C#での手動メモリマネージャー - 単なる研究

using System; 
using System.Runtime.InteropServices; 

namespace ConsoleApplication3 
{ 
    public unsafe static class MemoryHelper 
    { 
     [DllImport("kernel32.dll", SetLastError = true)] 
     static extern IntPtr GetProcessHeap(); 

     [DllImport("kernel32.dll", SetLastError = false)] 
     static extern void* HeapAlloc(IntPtr hHeap, uint dwFlags, UIntPtr dwBytes); 

     [DllImport("kernel32.dll")] 
     static extern void* HeapReAlloc(IntPtr hHeap, uint dwFlags, IntPtr lpMem, UIntPtr dwBytes); 

     [DllImport("kernel32.dll", SetLastError = true)] 
     static extern bool HeapFree(IntPtr hHeap, uint dwFlags, void* lpMem); 

     private static uint HEAP_REALLOC_IN_PLACE_ONLY = 0x00000010; 
     private static uint HEAP_NO_SERIALIZE = 0x00000001; 
     private static uint HEAP_ZERO_MEMORY = 0x00000008; 
     private static IntPtr Handle { get; set; } = GetProcessHeap(); 

     public static void* Malloc(uint size) 
     { 
      var tmp = HeapAlloc(Handle, HEAP_ZERO_MEMORY, new UIntPtr(size)); 
      if (tmp == null) 
       throw new Exception("Fail to allocate memory"); 
      return tmp; 
     } 

     public static void* Realloc(IntPtr blk, uint newSize) 
     { 
      var tmp = HeapReAlloc(Handle, HEAP_REALLOC_IN_PLACE_ONLY, blk, new UIntPtr(newSize)); 
      if (tmp == null) 
       throw new Exception("Fail to reallocate memory"); 
      return tmp; 
     } 

     public static bool Free(void* blk) 
     { 
      var ret = HeapFree(Handle, HEAP_NO_SERIALIZE, blk); 
      if (!ret) 
       throw new Exception("Fail to free memory"); 
      return ret; 
     } 
    } 

    unsafe public class Study 
    { 
     public Study() 
     { 
      UsingManualMemoryClass(); 
      Console.WriteLine("".PadLeft(80, '=')); 
      UsingMarshalClass(); 
     } 

     private static readonly object LockObj = new object(); 
     public void UsingManualMemoryClass() 
     { 
      int tamanho = 20; 
      int* teste = (int*)MemoryHelper.Malloc((uint)(sizeof(int) * tamanho)); 

      Random rnd = new Random(); 
      lock (LockObj) 
      { 
       for (int i = 0; i < tamanho; i++) 
        teste[i] = rnd.Next(0,8000); 
      } 

      for (int i = 0; i < tamanho; i++) 
       Console.WriteLine(teste[i]); 

      MemoryHelper.Free(teste); 

      Console.WriteLine("".PadLeft(80, '-')); 
      for (int i = 0; i < tamanho; i++) 
       Console.WriteLine(teste[i]); 
     } 

     public void UsingMarshalClass() 
     { 
      int tamanho = 20; 
      int* teste = (int*)Marshal.AllocHGlobal(sizeof(int) * tamanho); 

      Random rnd = new Random(); 
      lock (LockObj) 
      { 
       for (int i = 0; i < tamanho; i++) 
        teste[i] = rnd.Next(0, 8000); 
      } 

      for (int i = 0; i < tamanho; i++) 
       Console.WriteLine(teste[i]); 

      Marshal.FreeHGlobal((IntPtr)teste); 

      Console.WriteLine("".PadLeft(80, '-')); 
      for (int i = 0; i < tamanho; i++) 
       Console.WriteLine(teste[i]); 
     } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      new Study(); 
     } 
    } 
} 

これはどうしてですか?

----- EDIT

私はcodeprojectで、この記事を見つけた、と私はC++/CLIのコードを取得し、コードで簡単なDLLを作成し、アロケーションにネイティブCランタイムを使用するようにいくつかの変更を行なったし、無料メモリこれを行うにはネイティブC関数を使用して

#include <malloc.h> 
#include <stdlib.h>> 

using namespace System; 

namespace mm 
{ 
    public ref class Unmanaged abstract sealed 
    { 
    public: 
     generic <typename T> where T : value class 
      static void* New(int elementCount) 
     { 
      return malloc(sizeof(T) * elementCount); 
     } 

     static void Free(void* unmanagedPointer) 
     { 
      free(unmanagedPointer); 
     } 

     generic <typename T> where T : value class 
      static void* Resize(void* oldPointer, int newElementCount) 
     { 
      return realloc(oldPointer, (int)sizeof(T) * newElementCount); 
     } 
    }; 
} 

、私はWin32 API関数を呼び出すLocalFreeMarshal.FreeHGlobal無料...

+0

*これはなぜ発生するのですか?*管理されていない言語では、メモリを解放してもメモリにアクセスできます。それは未定義の振る舞いを引き起こしますが、あなたはそれを行うことができます。管理された言語は、この問題の解決策であると考えられています。 –

+0

私は、そのメモリがまだ再利用されておらず、上書きされていないという理由だけで動作すると考えています。最終的には再利用され、ごみ箱のデータや例外が発生します。一般的には、他のポインタベースのメモリアクセスと同じ考えです。このような愚かなことをすることができるので、C#はそれを* unsafe *と呼びます。 –

+0

* "これを修正する方法[...]?" * - 何も壊れていないので、何も修正する必要はありません。 – IInspectable

答えて

0

後にメモリにアクセスすることはできません。 LocalFreeを呼び出した後にメモリにアクセスしようとすると、未定義の動作が呼び出されます。その可能性のある結果:

  • 実行時エラーが発生する可能性があります。
  • 以前の状態のメモリにはまだアクセスできます。
  • メモリにはまだアクセスできますが、再使用されているため変更されている可能性があります。
  • ...

ほとんど何が起こることができ、あなたは何に頼ることはできません。

あなたの間違いは、解放後にメモリにアクセスできるということは、メモリが解放されていないことを意味します。その論理的控除は誤りであった。

関連する問題