How to find what is in unmanaged memory in Dump by WinDBGWhat is WinDbg <unknown> Memory?What exactly are unmanaged resources?Crash dump - resolve unmanaged code crash in a .NET application using WinDbgWinDbg and SoS, how do I print/dump a large string?Windbg - dumping System.GuidUsing WinDbg to analyze .NET dumpDumping array using WindbgWinDbg: Dump indicates CLR version that is used nowhereAnalyze dump file using WinDbg with SOS: How do I get the urls of all currently executing requests?Windbg loadin sos for UWP x64 dump (.loadby/.load)View managed stack from a full memory dump

Is the destination of a commercial flight important for the pilot?

Is a stroke of luck acceptable after a series of unfavorable events?

What does the word "Atten" mean?

Are student evaluations of teaching assistants read by others in the faculty?

Go Pregnant or Go Home

Two monoidal structures and copowering

Lay out the Carpet

Short story about space worker geeks who zone out by 'listening' to radiation from stars

Anatomically Correct Strange Women In Ponds Distributing Swords

How long to clear the 'suck zone' of a turbofan after start is initiated?

Is there a problem with hiding "forgot password" until it's needed?

Implement the Thanos sorting algorithm

Why escape if the_content isnt?

CREATE opcode: what does it really do?

Is this apparent Class Action settlement a spam message?

Balance Issues for a Custom Sorcerer Variant

India just shot down a satellite from the ground. At what altitude range is the resulting debris field?

How did Arya survive the stabbing?

Is `x >> pure y` equivalent to `liftM (const y) x`

Failed to fetch jessie backports repository

Class Action - which options I have?

How to Reset Passwords on Multiple Websites Easily?

Purchasing a ticket for someone else in another country?

Sort a list by elements of another list



How to find what is in unmanaged memory in Dump by WinDBG


What is WinDbg <unknown> Memory?What exactly are unmanaged resources?Crash dump - resolve unmanaged code crash in a .NET application using WinDbgWinDbg and SoS, how do I print/dump a large string?Windbg - dumping System.GuidUsing WinDbg to analyze .NET dumpDumping array using WindbgWinDbg: Dump indicates CLR version that is used nowhereAnalyze dump file using WinDbg with SOS: How do I get the urls of all currently executing requests?Windbg loadin sos for UWP x64 dump (.loadby/.load)View managed stack from a full memory dump













0















I run for Dump File in WinDbg command



!address -summary



I results are something like this



Usage Summary RgnCount Total Size %ofBusy %ofTota

Free 3739 7ff5`dbbae000 ( 127.960 Tb) 99.97%
<unknown> 1677 5`680a1000 ( 21.626 Gb) 53.31% 0.02%
Heap 20349 4`0049f000 ( 16.005 Gb) 39.45% 0.01%
Stack 230 0`a3e90000 ( 2.561 Gb) 6.31% 0.00%


How can I find what in in Heap? What are objects or what are types?



Is Managed Heap, and Heap is managed heap?





It is very hard to ask Questions Like this, so I added more info





Here is my C# Sample Code



class Program


public static int[] arr;
public static AllocateUnmanagedMemory cls;


static void Main(string[] args)

const int GBSize = 1 * 1024 * 1024 * 1024/ sizeof(int);

Console.WriteLine("Allocating");

arr = new int[GBSize];

cls = new AllocateUnmanagedMemory();

cls.UnmanagedAllocation();


Console.ReadLine();




Here is Unmanaged Allocation Code:



using System;
using System.Runtime.InteropServices;



public class AllocateUnmanagedMemory



static IntPtr pointer;

public void UnmanagedAllocation()

pointer = Marshal.AllocHGlobal(1024 * 1024 * 1024 );





And results from WinDbg Preview in Windows 10



-- Usage Summary RgnCount ----------- Total Size -------- %ofBusy %ofTotal
Free 59 762f7000 ( 1.847 GB) 46.17%
<unknown> 98 4493e000 ( 1.072 GB) 49.76% 26.79%
Heap 15 40158000 ( 1.001 GB) 46.50% 25.03%
Image 174 2db2000 ( 45.695 MB) 2.07% 1.12%
MappedFile 15 1c51000 ( 28.316 MB) 1.28% 0.69%
Stack 24 800000 ( 8.000 MB) 0.36% 0.20%


I should be able find somewhat that code for Unmanaged Allocation, allocated 1Gb memory.










share|improve this question




























    0















    I run for Dump File in WinDbg command



    !address -summary



    I results are something like this



    Usage Summary RgnCount Total Size %ofBusy %ofTota

    Free 3739 7ff5`dbbae000 ( 127.960 Tb) 99.97%
    <unknown> 1677 5`680a1000 ( 21.626 Gb) 53.31% 0.02%
    Heap 20349 4`0049f000 ( 16.005 Gb) 39.45% 0.01%
    Stack 230 0`a3e90000 ( 2.561 Gb) 6.31% 0.00%


    How can I find what in in Heap? What are objects or what are types?



    Is Managed Heap, and Heap is managed heap?





    It is very hard to ask Questions Like this, so I added more info





    Here is my C# Sample Code



    class Program


    public static int[] arr;
    public static AllocateUnmanagedMemory cls;


    static void Main(string[] args)

    const int GBSize = 1 * 1024 * 1024 * 1024/ sizeof(int);

    Console.WriteLine("Allocating");

    arr = new int[GBSize];

    cls = new AllocateUnmanagedMemory();

    cls.UnmanagedAllocation();


    Console.ReadLine();




    Here is Unmanaged Allocation Code:



    using System;
    using System.Runtime.InteropServices;



    public class AllocateUnmanagedMemory



    static IntPtr pointer;

    public void UnmanagedAllocation()

    pointer = Marshal.AllocHGlobal(1024 * 1024 * 1024 );





    And results from WinDbg Preview in Windows 10



    -- Usage Summary RgnCount ----------- Total Size -------- %ofBusy %ofTotal
    Free 59 762f7000 ( 1.847 GB) 46.17%
    <unknown> 98 4493e000 ( 1.072 GB) 49.76% 26.79%
    Heap 15 40158000 ( 1.001 GB) 46.50% 25.03%
    Image 174 2db2000 ( 45.695 MB) 2.07% 1.12%
    MappedFile 15 1c51000 ( 28.316 MB) 1.28% 0.69%
    Stack 24 800000 ( 8.000 MB) 0.36% 0.20%


    I should be able find somewhat that code for Unmanaged Allocation, allocated 1Gb memory.










    share|improve this question


























      0












      0








      0


      1






      I run for Dump File in WinDbg command



      !address -summary



      I results are something like this



      Usage Summary RgnCount Total Size %ofBusy %ofTota

      Free 3739 7ff5`dbbae000 ( 127.960 Tb) 99.97%
      <unknown> 1677 5`680a1000 ( 21.626 Gb) 53.31% 0.02%
      Heap 20349 4`0049f000 ( 16.005 Gb) 39.45% 0.01%
      Stack 230 0`a3e90000 ( 2.561 Gb) 6.31% 0.00%


      How can I find what in in Heap? What are objects or what are types?



      Is Managed Heap, and Heap is managed heap?





      It is very hard to ask Questions Like this, so I added more info





      Here is my C# Sample Code



      class Program


      public static int[] arr;
      public static AllocateUnmanagedMemory cls;


      static void Main(string[] args)

      const int GBSize = 1 * 1024 * 1024 * 1024/ sizeof(int);

      Console.WriteLine("Allocating");

      arr = new int[GBSize];

      cls = new AllocateUnmanagedMemory();

      cls.UnmanagedAllocation();


      Console.ReadLine();




      Here is Unmanaged Allocation Code:



      using System;
      using System.Runtime.InteropServices;



      public class AllocateUnmanagedMemory



      static IntPtr pointer;

      public void UnmanagedAllocation()

      pointer = Marshal.AllocHGlobal(1024 * 1024 * 1024 );





      And results from WinDbg Preview in Windows 10



      -- Usage Summary RgnCount ----------- Total Size -------- %ofBusy %ofTotal
      Free 59 762f7000 ( 1.847 GB) 46.17%
      <unknown> 98 4493e000 ( 1.072 GB) 49.76% 26.79%
      Heap 15 40158000 ( 1.001 GB) 46.50% 25.03%
      Image 174 2db2000 ( 45.695 MB) 2.07% 1.12%
      MappedFile 15 1c51000 ( 28.316 MB) 1.28% 0.69%
      Stack 24 800000 ( 8.000 MB) 0.36% 0.20%


      I should be able find somewhat that code for Unmanaged Allocation, allocated 1Gb memory.










      share|improve this question
















      I run for Dump File in WinDbg command



      !address -summary



      I results are something like this



      Usage Summary RgnCount Total Size %ofBusy %ofTota

      Free 3739 7ff5`dbbae000 ( 127.960 Tb) 99.97%
      <unknown> 1677 5`680a1000 ( 21.626 Gb) 53.31% 0.02%
      Heap 20349 4`0049f000 ( 16.005 Gb) 39.45% 0.01%
      Stack 230 0`a3e90000 ( 2.561 Gb) 6.31% 0.00%


      How can I find what in in Heap? What are objects or what are types?



      Is Managed Heap, and Heap is managed heap?





      It is very hard to ask Questions Like this, so I added more info





      Here is my C# Sample Code



      class Program


      public static int[] arr;
      public static AllocateUnmanagedMemory cls;


      static void Main(string[] args)

      const int GBSize = 1 * 1024 * 1024 * 1024/ sizeof(int);

      Console.WriteLine("Allocating");

      arr = new int[GBSize];

      cls = new AllocateUnmanagedMemory();

      cls.UnmanagedAllocation();


      Console.ReadLine();




      Here is Unmanaged Allocation Code:



      using System;
      using System.Runtime.InteropServices;



      public class AllocateUnmanagedMemory



      static IntPtr pointer;

      public void UnmanagedAllocation()

      pointer = Marshal.AllocHGlobal(1024 * 1024 * 1024 );





      And results from WinDbg Preview in Windows 10



      -- Usage Summary RgnCount ----------- Total Size -------- %ofBusy %ofTotal
      Free 59 762f7000 ( 1.847 GB) 46.17%
      <unknown> 98 4493e000 ( 1.072 GB) 49.76% 26.79%
      Heap 15 40158000 ( 1.001 GB) 46.50% 25.03%
      Image 174 2db2000 ( 45.695 MB) 2.07% 1.12%
      MappedFile 15 1c51000 ( 28.316 MB) 1.28% 0.69%
      Stack 24 800000 ( 8.000 MB) 0.36% 0.20%


      I should be able find somewhat that code for Unmanaged Allocation, allocated 1Gb memory.







      heap windbg unmanaged dump sos






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Mar 8 at 17:29







      justromagod

















      asked Mar 7 at 12:32









      justromagodjustromagod

      322211




      322211






















          1 Answer
          1






          active

          oldest

          votes


















          2














          The basics



          The command !address operates on a very low level, barely above the operating system. However, it will recognize a little bit of the memory manager that comes with Windows: the Windows Heap Manager.



          So, what you see as Heap that is memory which was allocated through the Windows Heap manager. On your level of understanding, that's the native heap.



          Any other heap managers will implement their own memory management. Basically they all work similar: they get large blocks of memory from VirtualAlloc() and then try to do a better magement of the small blocks within that large block. Since WinDbg doesn't know any of these memory managers, that memory is declared as <unknown>. It includes, but is not limited to the managed heap of .NET. For other potential uses, see this answer.



          Free is memory that can potentially be claimed from the operating system. This may include swap space, not only physical RAM.



          Stack, well that's obvious I think.



          The heaps




          How can I find what in in Heap? What are objects or what are types?




          The answer to this question heavily depends on which heap you're talking about.



          The Windows Heap Manager ("native heap") just manages memory and does not manage types. It's not possible on that level to distinguish two objects of the same size but different type. If you have a memory leak, you can only give a statement like "I have a leak of n bytes". To find our more about the native heap, start with !heap -s and look up the other !heap commands.



          The .NET managed heap retains a type system. To analyze the managed heap, you need an extension for WinDbg called sos. Usually you load it by .loadby sos clr. It has a command !dumpheap -stat which may give you a first impression of its capabilities. (Run the command twice if you get an error message)



          This should give you enough hints to do further research and find more details in your crash dump.



          Strange?



          You seem to have 230 stacks with a total of 2.5 GB of memory. That is about 11 MB of memory per stack. Usually that's limited to 1 MB.



          Your updated example code



          I compiled the following program



          using System;
          using System.Runtime.InteropServices;
          namespace SO55043889

          class Program

          public static int[] arr;
          static IntPtr pointer;
          static void Main()

          const int GBSize = 1 * 1024 * 1024 * 1024/ sizeof(int);
          Console.WriteLine("Allocating");
          arr = new int[GBSize];
          pointer = Marshal.AllocHGlobal(1024 * 1024 * 1024 );
          Console.ReadLine();
          Console.WriteLine(pointer.ToInt32() + arr[0]);





          I ran the application and I attached to the process with WinDbg. I took a dump using



          0:000> .dump /ma SO55043889.dmp


          and now we can analyze it like this:



          0:000> !address -summary
          [...]
          <unknown> 106 474f4000 ( 1.114 GB) 51.58% 27.86%
          Heap 13 401e1000 ( 1.002 GB) 46.38% 25.05%
          [...]


          So we see 1 GB of (potentially) .NET memory and 1 GB of native memory.



          0:000> .loadby sos clr
          0:000> !dumpheap -stat
          c0000005 Exception in C:WindowsMicrosoft.NETFrameworkv4.0.30319sos.dumpheap debugger extension.
          PC: 04f6fa73 VA: 00000000 R/W: 0 Parameter: 00000000
          0:000> *** This is normal, just do it again
          0:000> !dumpheap -stat
          [...]
          70d20958 12 1073742400 System.Int32[]
          Total 335 objects


          There are 12 int[] on the .NET side, taking a total of ~1 GB from the managed heap. Looking at the details, we see that there's only one big array and some smaller ones:



          0:000> !dumpheap -type System.Int32[]
          Address MT Size
          020e1ff8 70d20958 300
          020e2130 70d20958 24
          020e2184 70d20958 40
          020e2228 70d20958 80
          020e2d9c 70d20958 16
          020e2dac 70d20958 16
          020e2df8 70d20958 16
          020e386c 70d20958 24
          020e3d54 70d20958 16
          020e3d64 70d20958 16
          020e3d74 70d20958 16
          04811010 70d20958 1073741836

          Statistics:
          MT Count TotalSize Class Name
          70d20958 12 1073742400 System.Int32[]
          Total 12 objects


          That's not what you wanted know. I just showed you how easy it is on the .NET side.



          Now the native side:



          0:004> !heap -s
          LFH Key : 0x7f8d0cc6
          Termination on corruption : ENABLED
          Heap Flags Reserv Commit Virt Free List UCR Virt Lock Fast
          (k) (k) (k) (k) length blocks cont. heap
          -----------------------------------------------------------------------------
          Virtual block: 80010000 - 80010000 (size 00000000)
          00550000 00000002 1024 504 1024 14 17 1 1 0 LFH
          002d0000 00001002 64 16 64 2 2 1 0 0
          00820000 00041002 256 4 256 2 1 1 0 0
          00750000 00001002 64 20 64 7 2 1 0 0
          00710000 00001002 256 4 256 0 1 1 0 0
          001e0000 00041002 256 4 256 2 1 1 0 0
          -----------------------------------------------------------------------------


          We can't see the 1 GB here. And there's a reason for that.



          As explained before, heap managers are good at dividing large blocks from VirtualAlloc() (which are 64kB) into smaller pieces. They do that because it would be a big waste to allocate 64kB just for a 4 byte int. However, there's no need to create heap management stucture for large blocks. For an allocation of 2^30+1 byte, the OS would return 2^30+64kB, which means the overhead is just 0.006%.



          That's why you will find allocations >512kB not inside the usual heap management structures but as a Virtual block, which means that the Windows Heap Manager has simply forwarded the request to VirtualAlloc().



          There's another issue here: the output for the size is broken. It says



          (size 00000000)


          which obviously is not true. Let's look at it ourselves:



          0:004> !address 80010000 
          Usage: Heap
          Base Address: 80010000
          End Address: c0011000
          Region Size: 40001000
          [...]

          0:004> ? c0011000-80010000
          Evaluate expression: 1073745920 = 40001000


          What we see here is that End Adress - Base Address equals the Region Size and the size is 1 GB.



          At this point, it's worth noting that the user mode stack trace database is useless. It only applies to items on the heap, but not VirtualAlloc(). You'll not figure out who allocated the 1 GB block.



          And I forgot to enable the user mode stack trace database anyway. Let's do that and cross check



          0:000> !gflag
          Current NtGlobalFlag contents: 0x00001000
          ust - Create user mode stack trace database


          And now, there should be stack traces for smaller pieces of memory. In this example, I use an arbitrary block of size 0x208:



          0:000> !heap -flt s 208
          _HEAP @ 2a0000
          HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
          002c9818 0044 0000 [00] 002c9830 00208 - (busy)
          002cd1e8 0044 0044 [00] 002cd200 00208 - (busy)
          002d5ad0 0044 0044 [00] 002d5ae8 00208 - (busy)
          002f0c48 0044 0044 [00] 002f0c60 00208 - (busy)
          0032c210 0044 0044 [00] 0032c228 00208 - (busy)
          00351c90 0044 0044 [00] 00351ca8 00208 - (busy)
          0:000> *** Use any UserPtr number, I use the last one
          0:000> !heap -p -a 00351ca8
          address 00351ca8 found in
          _HEAP @ 2a0000
          HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
          00351c90 0044 0000 [00] 00351ca8 00208 - (busy)
          779dd909 ntdll!RtlAllocateHeap+0x00000274
          71e18bc7 clr!EEHeapAlloc+0x0000002c
          71e18c0a clr!EEHeapAllocInProcessHeap+0x0000005b
          71e18ba6 clr!ClrAllocInProcessHeap+0x00000023
          71e2dd26 clr!StackingAllocator::AllocNewBlockForBytes+0x00000082
          71e2dd76 clr!operator new+0x00000063
          71e93ace clr!MethodTableBuilder::BuildMethodTableThrowing+0x00000059
          71e94590 clr!ClassLoader::CreateTypeHandleForTypeDefThrowing+0x0000083a
          71e2e956 clr!ClassLoader::CreateTypeHandleForTypeKey+0x000000ad
          71e2e99a clr!ClassLoader::DoIncrementalLoad+0x000000c2
          71e2e418 clr!ClassLoader::LoadTypeHandleForTypeKey_Body+0x00000505
          71e2e5a7 clr!ClassLoader::LoadTypeHandleForTypeKey+0x000000b5
          71e2f723 clr!ClassLoader::LoadTypeDefThrowing+0x00000318
          71e2a974 clr!ClassLoader::LoadTypeDefOrRefThrowing+0x0000024c
          71f57811 clr!Assembly::GetEntryPoint+0x0000022f
          71f856e0 clr!Assembly::ExecuteMainMethod+0x000000b3
          71f855ed clr!SystemDomain::ExecuteMainMethod+0x00000631
          71f858d3 clr!ExecuteEXE+0x0000004c
          71f85819 clr!_CorExeMainInternal+0x000000dc
          71f55a0c clr!_CorExeMain+0x0000004d
          7251d93b mscoreei!_CorExeMain+0x0000010e
          72597f16 MSCOREE!ShellShim__CorExeMain+0x00000099
          72594de3 MSCOREE!_CorExeMain_Exported+0x00000008
          77999802 ntdll!__RtlUserThreadStart+0x00000070
          779997d5 ntdll!_RtlUserThreadStart+0x0000001b


          Just one more note: if you modify the program to have smaller blocks of memory, e.g.



          for (int i = 0; i < 1000; i++)

          pointer = Marshal.AllocHGlobal(3*1024 );



          You will see the allocation in the heap:



          0:004> ? 3*0n1024
          Evaluate expression: 3072 = 00000c00
          0:004> !heap -flt c00
          cound not parse flt criteria -flt c00
          0:004> !heap -flt s c00
          _HEAP @ 67c0000
          HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
          0686b668 0183 0000 [00] 0686b680 00c00 - (busy)
          0686efa8 0183 0183 [00] 0686efc0 00c00 - (busy)
          [...]


          And you will see stack traces



          0:004> !heap -p -a 4d0fdf18 
          address 4d0fdf18 found in
          _HEAP @ 67c0000
          HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
          4d0fdf00 0191 0000 [00] 4d0fdf18 00c00 - (busy)
          779dd909 ntdll!RtlAllocateHeap+0x00000274
          768f5aae KERNELBASE!LocalAlloc+0x0000005f
          70c6ad4f mscorlib_ni+0x003fad4f
          7138c4da mscorlib_ni+0x00b1c4da
          71e0ebb6 clr!CallDescrWorkerInternal+0x00000034
          71e11e10 clr!CallDescrWorkerWithHandler+0x0000006b
          71e17994 clr!MethodDescCallSite::CallTargetWorker+0x0000016a
          71f85026 clr!RunMain+0x000001ad
          71f85707 clr!Assembly::ExecuteMainMethod+0x00000124
          [...]


          But you won't see the managed method calls. That's because the USt database was built for native only. It's the same reason you have different stacks in .NET using k or !dumpstack.






          share|improve this answer

























          • I added sample code, your answer absolutely correct, if we don't know what is in <Heap> , it is just bytes. But in real word we always have some DLL(s) referenced, and code which allocate Unmanaged memory, It is just very hard to identify this DLL(s) and code. And this is what I am looking for. Find who allocated 1GB code in sample.( or 14 Gb in first example)

            – justromagod
            Mar 8 at 17:32












          • So it works! I am eager waiting to check it real life. Thank you a lot!

            – justromagod
            Mar 9 at 14:26











          • @justromagod: I just added another note regarding the NET stack

            – Thomas Weller
            Mar 9 at 14:26











          • it seems without gflag enabled, all my dumps are useless.

            – justromagod
            Mar 11 at 14:34











          • @justromagod: yes

            – Thomas Weller
            Mar 11 at 14:42










          Your Answer






          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "1"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader:
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          ,
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );













          draft saved

          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55043889%2fhow-to-find-what-is-in-unmanaged-memory-in-dump-by-windbg%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          2














          The basics



          The command !address operates on a very low level, barely above the operating system. However, it will recognize a little bit of the memory manager that comes with Windows: the Windows Heap Manager.



          So, what you see as Heap that is memory which was allocated through the Windows Heap manager. On your level of understanding, that's the native heap.



          Any other heap managers will implement their own memory management. Basically they all work similar: they get large blocks of memory from VirtualAlloc() and then try to do a better magement of the small blocks within that large block. Since WinDbg doesn't know any of these memory managers, that memory is declared as <unknown>. It includes, but is not limited to the managed heap of .NET. For other potential uses, see this answer.



          Free is memory that can potentially be claimed from the operating system. This may include swap space, not only physical RAM.



          Stack, well that's obvious I think.



          The heaps




          How can I find what in in Heap? What are objects or what are types?




          The answer to this question heavily depends on which heap you're talking about.



          The Windows Heap Manager ("native heap") just manages memory and does not manage types. It's not possible on that level to distinguish two objects of the same size but different type. If you have a memory leak, you can only give a statement like "I have a leak of n bytes". To find our more about the native heap, start with !heap -s and look up the other !heap commands.



          The .NET managed heap retains a type system. To analyze the managed heap, you need an extension for WinDbg called sos. Usually you load it by .loadby sos clr. It has a command !dumpheap -stat which may give you a first impression of its capabilities. (Run the command twice if you get an error message)



          This should give you enough hints to do further research and find more details in your crash dump.



          Strange?



          You seem to have 230 stacks with a total of 2.5 GB of memory. That is about 11 MB of memory per stack. Usually that's limited to 1 MB.



          Your updated example code



          I compiled the following program



          using System;
          using System.Runtime.InteropServices;
          namespace SO55043889

          class Program

          public static int[] arr;
          static IntPtr pointer;
          static void Main()

          const int GBSize = 1 * 1024 * 1024 * 1024/ sizeof(int);
          Console.WriteLine("Allocating");
          arr = new int[GBSize];
          pointer = Marshal.AllocHGlobal(1024 * 1024 * 1024 );
          Console.ReadLine();
          Console.WriteLine(pointer.ToInt32() + arr[0]);





          I ran the application and I attached to the process with WinDbg. I took a dump using



          0:000> .dump /ma SO55043889.dmp


          and now we can analyze it like this:



          0:000> !address -summary
          [...]
          <unknown> 106 474f4000 ( 1.114 GB) 51.58% 27.86%
          Heap 13 401e1000 ( 1.002 GB) 46.38% 25.05%
          [...]


          So we see 1 GB of (potentially) .NET memory and 1 GB of native memory.



          0:000> .loadby sos clr
          0:000> !dumpheap -stat
          c0000005 Exception in C:WindowsMicrosoft.NETFrameworkv4.0.30319sos.dumpheap debugger extension.
          PC: 04f6fa73 VA: 00000000 R/W: 0 Parameter: 00000000
          0:000> *** This is normal, just do it again
          0:000> !dumpheap -stat
          [...]
          70d20958 12 1073742400 System.Int32[]
          Total 335 objects


          There are 12 int[] on the .NET side, taking a total of ~1 GB from the managed heap. Looking at the details, we see that there's only one big array and some smaller ones:



          0:000> !dumpheap -type System.Int32[]
          Address MT Size
          020e1ff8 70d20958 300
          020e2130 70d20958 24
          020e2184 70d20958 40
          020e2228 70d20958 80
          020e2d9c 70d20958 16
          020e2dac 70d20958 16
          020e2df8 70d20958 16
          020e386c 70d20958 24
          020e3d54 70d20958 16
          020e3d64 70d20958 16
          020e3d74 70d20958 16
          04811010 70d20958 1073741836

          Statistics:
          MT Count TotalSize Class Name
          70d20958 12 1073742400 System.Int32[]
          Total 12 objects


          That's not what you wanted know. I just showed you how easy it is on the .NET side.



          Now the native side:



          0:004> !heap -s
          LFH Key : 0x7f8d0cc6
          Termination on corruption : ENABLED
          Heap Flags Reserv Commit Virt Free List UCR Virt Lock Fast
          (k) (k) (k) (k) length blocks cont. heap
          -----------------------------------------------------------------------------
          Virtual block: 80010000 - 80010000 (size 00000000)
          00550000 00000002 1024 504 1024 14 17 1 1 0 LFH
          002d0000 00001002 64 16 64 2 2 1 0 0
          00820000 00041002 256 4 256 2 1 1 0 0
          00750000 00001002 64 20 64 7 2 1 0 0
          00710000 00001002 256 4 256 0 1 1 0 0
          001e0000 00041002 256 4 256 2 1 1 0 0
          -----------------------------------------------------------------------------


          We can't see the 1 GB here. And there's a reason for that.



          As explained before, heap managers are good at dividing large blocks from VirtualAlloc() (which are 64kB) into smaller pieces. They do that because it would be a big waste to allocate 64kB just for a 4 byte int. However, there's no need to create heap management stucture for large blocks. For an allocation of 2^30+1 byte, the OS would return 2^30+64kB, which means the overhead is just 0.006%.



          That's why you will find allocations >512kB not inside the usual heap management structures but as a Virtual block, which means that the Windows Heap Manager has simply forwarded the request to VirtualAlloc().



          There's another issue here: the output for the size is broken. It says



          (size 00000000)


          which obviously is not true. Let's look at it ourselves:



          0:004> !address 80010000 
          Usage: Heap
          Base Address: 80010000
          End Address: c0011000
          Region Size: 40001000
          [...]

          0:004> ? c0011000-80010000
          Evaluate expression: 1073745920 = 40001000


          What we see here is that End Adress - Base Address equals the Region Size and the size is 1 GB.



          At this point, it's worth noting that the user mode stack trace database is useless. It only applies to items on the heap, but not VirtualAlloc(). You'll not figure out who allocated the 1 GB block.



          And I forgot to enable the user mode stack trace database anyway. Let's do that and cross check



          0:000> !gflag
          Current NtGlobalFlag contents: 0x00001000
          ust - Create user mode stack trace database


          And now, there should be stack traces for smaller pieces of memory. In this example, I use an arbitrary block of size 0x208:



          0:000> !heap -flt s 208
          _HEAP @ 2a0000
          HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
          002c9818 0044 0000 [00] 002c9830 00208 - (busy)
          002cd1e8 0044 0044 [00] 002cd200 00208 - (busy)
          002d5ad0 0044 0044 [00] 002d5ae8 00208 - (busy)
          002f0c48 0044 0044 [00] 002f0c60 00208 - (busy)
          0032c210 0044 0044 [00] 0032c228 00208 - (busy)
          00351c90 0044 0044 [00] 00351ca8 00208 - (busy)
          0:000> *** Use any UserPtr number, I use the last one
          0:000> !heap -p -a 00351ca8
          address 00351ca8 found in
          _HEAP @ 2a0000
          HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
          00351c90 0044 0000 [00] 00351ca8 00208 - (busy)
          779dd909 ntdll!RtlAllocateHeap+0x00000274
          71e18bc7 clr!EEHeapAlloc+0x0000002c
          71e18c0a clr!EEHeapAllocInProcessHeap+0x0000005b
          71e18ba6 clr!ClrAllocInProcessHeap+0x00000023
          71e2dd26 clr!StackingAllocator::AllocNewBlockForBytes+0x00000082
          71e2dd76 clr!operator new+0x00000063
          71e93ace clr!MethodTableBuilder::BuildMethodTableThrowing+0x00000059
          71e94590 clr!ClassLoader::CreateTypeHandleForTypeDefThrowing+0x0000083a
          71e2e956 clr!ClassLoader::CreateTypeHandleForTypeKey+0x000000ad
          71e2e99a clr!ClassLoader::DoIncrementalLoad+0x000000c2
          71e2e418 clr!ClassLoader::LoadTypeHandleForTypeKey_Body+0x00000505
          71e2e5a7 clr!ClassLoader::LoadTypeHandleForTypeKey+0x000000b5
          71e2f723 clr!ClassLoader::LoadTypeDefThrowing+0x00000318
          71e2a974 clr!ClassLoader::LoadTypeDefOrRefThrowing+0x0000024c
          71f57811 clr!Assembly::GetEntryPoint+0x0000022f
          71f856e0 clr!Assembly::ExecuteMainMethod+0x000000b3
          71f855ed clr!SystemDomain::ExecuteMainMethod+0x00000631
          71f858d3 clr!ExecuteEXE+0x0000004c
          71f85819 clr!_CorExeMainInternal+0x000000dc
          71f55a0c clr!_CorExeMain+0x0000004d
          7251d93b mscoreei!_CorExeMain+0x0000010e
          72597f16 MSCOREE!ShellShim__CorExeMain+0x00000099
          72594de3 MSCOREE!_CorExeMain_Exported+0x00000008
          77999802 ntdll!__RtlUserThreadStart+0x00000070
          779997d5 ntdll!_RtlUserThreadStart+0x0000001b


          Just one more note: if you modify the program to have smaller blocks of memory, e.g.



          for (int i = 0; i < 1000; i++)

          pointer = Marshal.AllocHGlobal(3*1024 );



          You will see the allocation in the heap:



          0:004> ? 3*0n1024
          Evaluate expression: 3072 = 00000c00
          0:004> !heap -flt c00
          cound not parse flt criteria -flt c00
          0:004> !heap -flt s c00
          _HEAP @ 67c0000
          HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
          0686b668 0183 0000 [00] 0686b680 00c00 - (busy)
          0686efa8 0183 0183 [00] 0686efc0 00c00 - (busy)
          [...]


          And you will see stack traces



          0:004> !heap -p -a 4d0fdf18 
          address 4d0fdf18 found in
          _HEAP @ 67c0000
          HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
          4d0fdf00 0191 0000 [00] 4d0fdf18 00c00 - (busy)
          779dd909 ntdll!RtlAllocateHeap+0x00000274
          768f5aae KERNELBASE!LocalAlloc+0x0000005f
          70c6ad4f mscorlib_ni+0x003fad4f
          7138c4da mscorlib_ni+0x00b1c4da
          71e0ebb6 clr!CallDescrWorkerInternal+0x00000034
          71e11e10 clr!CallDescrWorkerWithHandler+0x0000006b
          71e17994 clr!MethodDescCallSite::CallTargetWorker+0x0000016a
          71f85026 clr!RunMain+0x000001ad
          71f85707 clr!Assembly::ExecuteMainMethod+0x00000124
          [...]


          But you won't see the managed method calls. That's because the USt database was built for native only. It's the same reason you have different stacks in .NET using k or !dumpstack.






          share|improve this answer

























          • I added sample code, your answer absolutely correct, if we don't know what is in <Heap> , it is just bytes. But in real word we always have some DLL(s) referenced, and code which allocate Unmanaged memory, It is just very hard to identify this DLL(s) and code. And this is what I am looking for. Find who allocated 1GB code in sample.( or 14 Gb in first example)

            – justromagod
            Mar 8 at 17:32












          • So it works! I am eager waiting to check it real life. Thank you a lot!

            – justromagod
            Mar 9 at 14:26











          • @justromagod: I just added another note regarding the NET stack

            – Thomas Weller
            Mar 9 at 14:26











          • it seems without gflag enabled, all my dumps are useless.

            – justromagod
            Mar 11 at 14:34











          • @justromagod: yes

            – Thomas Weller
            Mar 11 at 14:42















          2














          The basics



          The command !address operates on a very low level, barely above the operating system. However, it will recognize a little bit of the memory manager that comes with Windows: the Windows Heap Manager.



          So, what you see as Heap that is memory which was allocated through the Windows Heap manager. On your level of understanding, that's the native heap.



          Any other heap managers will implement their own memory management. Basically they all work similar: they get large blocks of memory from VirtualAlloc() and then try to do a better magement of the small blocks within that large block. Since WinDbg doesn't know any of these memory managers, that memory is declared as <unknown>. It includes, but is not limited to the managed heap of .NET. For other potential uses, see this answer.



          Free is memory that can potentially be claimed from the operating system. This may include swap space, not only physical RAM.



          Stack, well that's obvious I think.



          The heaps




          How can I find what in in Heap? What are objects or what are types?




          The answer to this question heavily depends on which heap you're talking about.



          The Windows Heap Manager ("native heap") just manages memory and does not manage types. It's not possible on that level to distinguish two objects of the same size but different type. If you have a memory leak, you can only give a statement like "I have a leak of n bytes". To find our more about the native heap, start with !heap -s and look up the other !heap commands.



          The .NET managed heap retains a type system. To analyze the managed heap, you need an extension for WinDbg called sos. Usually you load it by .loadby sos clr. It has a command !dumpheap -stat which may give you a first impression of its capabilities. (Run the command twice if you get an error message)



          This should give you enough hints to do further research and find more details in your crash dump.



          Strange?



          You seem to have 230 stacks with a total of 2.5 GB of memory. That is about 11 MB of memory per stack. Usually that's limited to 1 MB.



          Your updated example code



          I compiled the following program



          using System;
          using System.Runtime.InteropServices;
          namespace SO55043889

          class Program

          public static int[] arr;
          static IntPtr pointer;
          static void Main()

          const int GBSize = 1 * 1024 * 1024 * 1024/ sizeof(int);
          Console.WriteLine("Allocating");
          arr = new int[GBSize];
          pointer = Marshal.AllocHGlobal(1024 * 1024 * 1024 );
          Console.ReadLine();
          Console.WriteLine(pointer.ToInt32() + arr[0]);





          I ran the application and I attached to the process with WinDbg. I took a dump using



          0:000> .dump /ma SO55043889.dmp


          and now we can analyze it like this:



          0:000> !address -summary
          [...]
          <unknown> 106 474f4000 ( 1.114 GB) 51.58% 27.86%
          Heap 13 401e1000 ( 1.002 GB) 46.38% 25.05%
          [...]


          So we see 1 GB of (potentially) .NET memory and 1 GB of native memory.



          0:000> .loadby sos clr
          0:000> !dumpheap -stat
          c0000005 Exception in C:WindowsMicrosoft.NETFrameworkv4.0.30319sos.dumpheap debugger extension.
          PC: 04f6fa73 VA: 00000000 R/W: 0 Parameter: 00000000
          0:000> *** This is normal, just do it again
          0:000> !dumpheap -stat
          [...]
          70d20958 12 1073742400 System.Int32[]
          Total 335 objects


          There are 12 int[] on the .NET side, taking a total of ~1 GB from the managed heap. Looking at the details, we see that there's only one big array and some smaller ones:



          0:000> !dumpheap -type System.Int32[]
          Address MT Size
          020e1ff8 70d20958 300
          020e2130 70d20958 24
          020e2184 70d20958 40
          020e2228 70d20958 80
          020e2d9c 70d20958 16
          020e2dac 70d20958 16
          020e2df8 70d20958 16
          020e386c 70d20958 24
          020e3d54 70d20958 16
          020e3d64 70d20958 16
          020e3d74 70d20958 16
          04811010 70d20958 1073741836

          Statistics:
          MT Count TotalSize Class Name
          70d20958 12 1073742400 System.Int32[]
          Total 12 objects


          That's not what you wanted know. I just showed you how easy it is on the .NET side.



          Now the native side:



          0:004> !heap -s
          LFH Key : 0x7f8d0cc6
          Termination on corruption : ENABLED
          Heap Flags Reserv Commit Virt Free List UCR Virt Lock Fast
          (k) (k) (k) (k) length blocks cont. heap
          -----------------------------------------------------------------------------
          Virtual block: 80010000 - 80010000 (size 00000000)
          00550000 00000002 1024 504 1024 14 17 1 1 0 LFH
          002d0000 00001002 64 16 64 2 2 1 0 0
          00820000 00041002 256 4 256 2 1 1 0 0
          00750000 00001002 64 20 64 7 2 1 0 0
          00710000 00001002 256 4 256 0 1 1 0 0
          001e0000 00041002 256 4 256 2 1 1 0 0
          -----------------------------------------------------------------------------


          We can't see the 1 GB here. And there's a reason for that.



          As explained before, heap managers are good at dividing large blocks from VirtualAlloc() (which are 64kB) into smaller pieces. They do that because it would be a big waste to allocate 64kB just for a 4 byte int. However, there's no need to create heap management stucture for large blocks. For an allocation of 2^30+1 byte, the OS would return 2^30+64kB, which means the overhead is just 0.006%.



          That's why you will find allocations >512kB not inside the usual heap management structures but as a Virtual block, which means that the Windows Heap Manager has simply forwarded the request to VirtualAlloc().



          There's another issue here: the output for the size is broken. It says



          (size 00000000)


          which obviously is not true. Let's look at it ourselves:



          0:004> !address 80010000 
          Usage: Heap
          Base Address: 80010000
          End Address: c0011000
          Region Size: 40001000
          [...]

          0:004> ? c0011000-80010000
          Evaluate expression: 1073745920 = 40001000


          What we see here is that End Adress - Base Address equals the Region Size and the size is 1 GB.



          At this point, it's worth noting that the user mode stack trace database is useless. It only applies to items on the heap, but not VirtualAlloc(). You'll not figure out who allocated the 1 GB block.



          And I forgot to enable the user mode stack trace database anyway. Let's do that and cross check



          0:000> !gflag
          Current NtGlobalFlag contents: 0x00001000
          ust - Create user mode stack trace database


          And now, there should be stack traces for smaller pieces of memory. In this example, I use an arbitrary block of size 0x208:



          0:000> !heap -flt s 208
          _HEAP @ 2a0000
          HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
          002c9818 0044 0000 [00] 002c9830 00208 - (busy)
          002cd1e8 0044 0044 [00] 002cd200 00208 - (busy)
          002d5ad0 0044 0044 [00] 002d5ae8 00208 - (busy)
          002f0c48 0044 0044 [00] 002f0c60 00208 - (busy)
          0032c210 0044 0044 [00] 0032c228 00208 - (busy)
          00351c90 0044 0044 [00] 00351ca8 00208 - (busy)
          0:000> *** Use any UserPtr number, I use the last one
          0:000> !heap -p -a 00351ca8
          address 00351ca8 found in
          _HEAP @ 2a0000
          HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
          00351c90 0044 0000 [00] 00351ca8 00208 - (busy)
          779dd909 ntdll!RtlAllocateHeap+0x00000274
          71e18bc7 clr!EEHeapAlloc+0x0000002c
          71e18c0a clr!EEHeapAllocInProcessHeap+0x0000005b
          71e18ba6 clr!ClrAllocInProcessHeap+0x00000023
          71e2dd26 clr!StackingAllocator::AllocNewBlockForBytes+0x00000082
          71e2dd76 clr!operator new+0x00000063
          71e93ace clr!MethodTableBuilder::BuildMethodTableThrowing+0x00000059
          71e94590 clr!ClassLoader::CreateTypeHandleForTypeDefThrowing+0x0000083a
          71e2e956 clr!ClassLoader::CreateTypeHandleForTypeKey+0x000000ad
          71e2e99a clr!ClassLoader::DoIncrementalLoad+0x000000c2
          71e2e418 clr!ClassLoader::LoadTypeHandleForTypeKey_Body+0x00000505
          71e2e5a7 clr!ClassLoader::LoadTypeHandleForTypeKey+0x000000b5
          71e2f723 clr!ClassLoader::LoadTypeDefThrowing+0x00000318
          71e2a974 clr!ClassLoader::LoadTypeDefOrRefThrowing+0x0000024c
          71f57811 clr!Assembly::GetEntryPoint+0x0000022f
          71f856e0 clr!Assembly::ExecuteMainMethod+0x000000b3
          71f855ed clr!SystemDomain::ExecuteMainMethod+0x00000631
          71f858d3 clr!ExecuteEXE+0x0000004c
          71f85819 clr!_CorExeMainInternal+0x000000dc
          71f55a0c clr!_CorExeMain+0x0000004d
          7251d93b mscoreei!_CorExeMain+0x0000010e
          72597f16 MSCOREE!ShellShim__CorExeMain+0x00000099
          72594de3 MSCOREE!_CorExeMain_Exported+0x00000008
          77999802 ntdll!__RtlUserThreadStart+0x00000070
          779997d5 ntdll!_RtlUserThreadStart+0x0000001b


          Just one more note: if you modify the program to have smaller blocks of memory, e.g.



          for (int i = 0; i < 1000; i++)

          pointer = Marshal.AllocHGlobal(3*1024 );



          You will see the allocation in the heap:



          0:004> ? 3*0n1024
          Evaluate expression: 3072 = 00000c00
          0:004> !heap -flt c00
          cound not parse flt criteria -flt c00
          0:004> !heap -flt s c00
          _HEAP @ 67c0000
          HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
          0686b668 0183 0000 [00] 0686b680 00c00 - (busy)
          0686efa8 0183 0183 [00] 0686efc0 00c00 - (busy)
          [...]


          And you will see stack traces



          0:004> !heap -p -a 4d0fdf18 
          address 4d0fdf18 found in
          _HEAP @ 67c0000
          HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
          4d0fdf00 0191 0000 [00] 4d0fdf18 00c00 - (busy)
          779dd909 ntdll!RtlAllocateHeap+0x00000274
          768f5aae KERNELBASE!LocalAlloc+0x0000005f
          70c6ad4f mscorlib_ni+0x003fad4f
          7138c4da mscorlib_ni+0x00b1c4da
          71e0ebb6 clr!CallDescrWorkerInternal+0x00000034
          71e11e10 clr!CallDescrWorkerWithHandler+0x0000006b
          71e17994 clr!MethodDescCallSite::CallTargetWorker+0x0000016a
          71f85026 clr!RunMain+0x000001ad
          71f85707 clr!Assembly::ExecuteMainMethod+0x00000124
          [...]


          But you won't see the managed method calls. That's because the USt database was built for native only. It's the same reason you have different stacks in .NET using k or !dumpstack.






          share|improve this answer

























          • I added sample code, your answer absolutely correct, if we don't know what is in <Heap> , it is just bytes. But in real word we always have some DLL(s) referenced, and code which allocate Unmanaged memory, It is just very hard to identify this DLL(s) and code. And this is what I am looking for. Find who allocated 1GB code in sample.( or 14 Gb in first example)

            – justromagod
            Mar 8 at 17:32












          • So it works! I am eager waiting to check it real life. Thank you a lot!

            – justromagod
            Mar 9 at 14:26











          • @justromagod: I just added another note regarding the NET stack

            – Thomas Weller
            Mar 9 at 14:26











          • it seems without gflag enabled, all my dumps are useless.

            – justromagod
            Mar 11 at 14:34











          • @justromagod: yes

            – Thomas Weller
            Mar 11 at 14:42













          2












          2








          2







          The basics



          The command !address operates on a very low level, barely above the operating system. However, it will recognize a little bit of the memory manager that comes with Windows: the Windows Heap Manager.



          So, what you see as Heap that is memory which was allocated through the Windows Heap manager. On your level of understanding, that's the native heap.



          Any other heap managers will implement their own memory management. Basically they all work similar: they get large blocks of memory from VirtualAlloc() and then try to do a better magement of the small blocks within that large block. Since WinDbg doesn't know any of these memory managers, that memory is declared as <unknown>. It includes, but is not limited to the managed heap of .NET. For other potential uses, see this answer.



          Free is memory that can potentially be claimed from the operating system. This may include swap space, not only physical RAM.



          Stack, well that's obvious I think.



          The heaps




          How can I find what in in Heap? What are objects or what are types?




          The answer to this question heavily depends on which heap you're talking about.



          The Windows Heap Manager ("native heap") just manages memory and does not manage types. It's not possible on that level to distinguish two objects of the same size but different type. If you have a memory leak, you can only give a statement like "I have a leak of n bytes". To find our more about the native heap, start with !heap -s and look up the other !heap commands.



          The .NET managed heap retains a type system. To analyze the managed heap, you need an extension for WinDbg called sos. Usually you load it by .loadby sos clr. It has a command !dumpheap -stat which may give you a first impression of its capabilities. (Run the command twice if you get an error message)



          This should give you enough hints to do further research and find more details in your crash dump.



          Strange?



          You seem to have 230 stacks with a total of 2.5 GB of memory. That is about 11 MB of memory per stack. Usually that's limited to 1 MB.



          Your updated example code



          I compiled the following program



          using System;
          using System.Runtime.InteropServices;
          namespace SO55043889

          class Program

          public static int[] arr;
          static IntPtr pointer;
          static void Main()

          const int GBSize = 1 * 1024 * 1024 * 1024/ sizeof(int);
          Console.WriteLine("Allocating");
          arr = new int[GBSize];
          pointer = Marshal.AllocHGlobal(1024 * 1024 * 1024 );
          Console.ReadLine();
          Console.WriteLine(pointer.ToInt32() + arr[0]);





          I ran the application and I attached to the process with WinDbg. I took a dump using



          0:000> .dump /ma SO55043889.dmp


          and now we can analyze it like this:



          0:000> !address -summary
          [...]
          <unknown> 106 474f4000 ( 1.114 GB) 51.58% 27.86%
          Heap 13 401e1000 ( 1.002 GB) 46.38% 25.05%
          [...]


          So we see 1 GB of (potentially) .NET memory and 1 GB of native memory.



          0:000> .loadby sos clr
          0:000> !dumpheap -stat
          c0000005 Exception in C:WindowsMicrosoft.NETFrameworkv4.0.30319sos.dumpheap debugger extension.
          PC: 04f6fa73 VA: 00000000 R/W: 0 Parameter: 00000000
          0:000> *** This is normal, just do it again
          0:000> !dumpheap -stat
          [...]
          70d20958 12 1073742400 System.Int32[]
          Total 335 objects


          There are 12 int[] on the .NET side, taking a total of ~1 GB from the managed heap. Looking at the details, we see that there's only one big array and some smaller ones:



          0:000> !dumpheap -type System.Int32[]
          Address MT Size
          020e1ff8 70d20958 300
          020e2130 70d20958 24
          020e2184 70d20958 40
          020e2228 70d20958 80
          020e2d9c 70d20958 16
          020e2dac 70d20958 16
          020e2df8 70d20958 16
          020e386c 70d20958 24
          020e3d54 70d20958 16
          020e3d64 70d20958 16
          020e3d74 70d20958 16
          04811010 70d20958 1073741836

          Statistics:
          MT Count TotalSize Class Name
          70d20958 12 1073742400 System.Int32[]
          Total 12 objects


          That's not what you wanted know. I just showed you how easy it is on the .NET side.



          Now the native side:



          0:004> !heap -s
          LFH Key : 0x7f8d0cc6
          Termination on corruption : ENABLED
          Heap Flags Reserv Commit Virt Free List UCR Virt Lock Fast
          (k) (k) (k) (k) length blocks cont. heap
          -----------------------------------------------------------------------------
          Virtual block: 80010000 - 80010000 (size 00000000)
          00550000 00000002 1024 504 1024 14 17 1 1 0 LFH
          002d0000 00001002 64 16 64 2 2 1 0 0
          00820000 00041002 256 4 256 2 1 1 0 0
          00750000 00001002 64 20 64 7 2 1 0 0
          00710000 00001002 256 4 256 0 1 1 0 0
          001e0000 00041002 256 4 256 2 1 1 0 0
          -----------------------------------------------------------------------------


          We can't see the 1 GB here. And there's a reason for that.



          As explained before, heap managers are good at dividing large blocks from VirtualAlloc() (which are 64kB) into smaller pieces. They do that because it would be a big waste to allocate 64kB just for a 4 byte int. However, there's no need to create heap management stucture for large blocks. For an allocation of 2^30+1 byte, the OS would return 2^30+64kB, which means the overhead is just 0.006%.



          That's why you will find allocations >512kB not inside the usual heap management structures but as a Virtual block, which means that the Windows Heap Manager has simply forwarded the request to VirtualAlloc().



          There's another issue here: the output for the size is broken. It says



          (size 00000000)


          which obviously is not true. Let's look at it ourselves:



          0:004> !address 80010000 
          Usage: Heap
          Base Address: 80010000
          End Address: c0011000
          Region Size: 40001000
          [...]

          0:004> ? c0011000-80010000
          Evaluate expression: 1073745920 = 40001000


          What we see here is that End Adress - Base Address equals the Region Size and the size is 1 GB.



          At this point, it's worth noting that the user mode stack trace database is useless. It only applies to items on the heap, but not VirtualAlloc(). You'll not figure out who allocated the 1 GB block.



          And I forgot to enable the user mode stack trace database anyway. Let's do that and cross check



          0:000> !gflag
          Current NtGlobalFlag contents: 0x00001000
          ust - Create user mode stack trace database


          And now, there should be stack traces for smaller pieces of memory. In this example, I use an arbitrary block of size 0x208:



          0:000> !heap -flt s 208
          _HEAP @ 2a0000
          HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
          002c9818 0044 0000 [00] 002c9830 00208 - (busy)
          002cd1e8 0044 0044 [00] 002cd200 00208 - (busy)
          002d5ad0 0044 0044 [00] 002d5ae8 00208 - (busy)
          002f0c48 0044 0044 [00] 002f0c60 00208 - (busy)
          0032c210 0044 0044 [00] 0032c228 00208 - (busy)
          00351c90 0044 0044 [00] 00351ca8 00208 - (busy)
          0:000> *** Use any UserPtr number, I use the last one
          0:000> !heap -p -a 00351ca8
          address 00351ca8 found in
          _HEAP @ 2a0000
          HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
          00351c90 0044 0000 [00] 00351ca8 00208 - (busy)
          779dd909 ntdll!RtlAllocateHeap+0x00000274
          71e18bc7 clr!EEHeapAlloc+0x0000002c
          71e18c0a clr!EEHeapAllocInProcessHeap+0x0000005b
          71e18ba6 clr!ClrAllocInProcessHeap+0x00000023
          71e2dd26 clr!StackingAllocator::AllocNewBlockForBytes+0x00000082
          71e2dd76 clr!operator new+0x00000063
          71e93ace clr!MethodTableBuilder::BuildMethodTableThrowing+0x00000059
          71e94590 clr!ClassLoader::CreateTypeHandleForTypeDefThrowing+0x0000083a
          71e2e956 clr!ClassLoader::CreateTypeHandleForTypeKey+0x000000ad
          71e2e99a clr!ClassLoader::DoIncrementalLoad+0x000000c2
          71e2e418 clr!ClassLoader::LoadTypeHandleForTypeKey_Body+0x00000505
          71e2e5a7 clr!ClassLoader::LoadTypeHandleForTypeKey+0x000000b5
          71e2f723 clr!ClassLoader::LoadTypeDefThrowing+0x00000318
          71e2a974 clr!ClassLoader::LoadTypeDefOrRefThrowing+0x0000024c
          71f57811 clr!Assembly::GetEntryPoint+0x0000022f
          71f856e0 clr!Assembly::ExecuteMainMethod+0x000000b3
          71f855ed clr!SystemDomain::ExecuteMainMethod+0x00000631
          71f858d3 clr!ExecuteEXE+0x0000004c
          71f85819 clr!_CorExeMainInternal+0x000000dc
          71f55a0c clr!_CorExeMain+0x0000004d
          7251d93b mscoreei!_CorExeMain+0x0000010e
          72597f16 MSCOREE!ShellShim__CorExeMain+0x00000099
          72594de3 MSCOREE!_CorExeMain_Exported+0x00000008
          77999802 ntdll!__RtlUserThreadStart+0x00000070
          779997d5 ntdll!_RtlUserThreadStart+0x0000001b


          Just one more note: if you modify the program to have smaller blocks of memory, e.g.



          for (int i = 0; i < 1000; i++)

          pointer = Marshal.AllocHGlobal(3*1024 );



          You will see the allocation in the heap:



          0:004> ? 3*0n1024
          Evaluate expression: 3072 = 00000c00
          0:004> !heap -flt c00
          cound not parse flt criteria -flt c00
          0:004> !heap -flt s c00
          _HEAP @ 67c0000
          HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
          0686b668 0183 0000 [00] 0686b680 00c00 - (busy)
          0686efa8 0183 0183 [00] 0686efc0 00c00 - (busy)
          [...]


          And you will see stack traces



          0:004> !heap -p -a 4d0fdf18 
          address 4d0fdf18 found in
          _HEAP @ 67c0000
          HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
          4d0fdf00 0191 0000 [00] 4d0fdf18 00c00 - (busy)
          779dd909 ntdll!RtlAllocateHeap+0x00000274
          768f5aae KERNELBASE!LocalAlloc+0x0000005f
          70c6ad4f mscorlib_ni+0x003fad4f
          7138c4da mscorlib_ni+0x00b1c4da
          71e0ebb6 clr!CallDescrWorkerInternal+0x00000034
          71e11e10 clr!CallDescrWorkerWithHandler+0x0000006b
          71e17994 clr!MethodDescCallSite::CallTargetWorker+0x0000016a
          71f85026 clr!RunMain+0x000001ad
          71f85707 clr!Assembly::ExecuteMainMethod+0x00000124
          [...]


          But you won't see the managed method calls. That's because the USt database was built for native only. It's the same reason you have different stacks in .NET using k or !dumpstack.






          share|improve this answer















          The basics



          The command !address operates on a very low level, barely above the operating system. However, it will recognize a little bit of the memory manager that comes with Windows: the Windows Heap Manager.



          So, what you see as Heap that is memory which was allocated through the Windows Heap manager. On your level of understanding, that's the native heap.



          Any other heap managers will implement their own memory management. Basically they all work similar: they get large blocks of memory from VirtualAlloc() and then try to do a better magement of the small blocks within that large block. Since WinDbg doesn't know any of these memory managers, that memory is declared as <unknown>. It includes, but is not limited to the managed heap of .NET. For other potential uses, see this answer.



          Free is memory that can potentially be claimed from the operating system. This may include swap space, not only physical RAM.



          Stack, well that's obvious I think.



          The heaps




          How can I find what in in Heap? What are objects or what are types?




          The answer to this question heavily depends on which heap you're talking about.



          The Windows Heap Manager ("native heap") just manages memory and does not manage types. It's not possible on that level to distinguish two objects of the same size but different type. If you have a memory leak, you can only give a statement like "I have a leak of n bytes". To find our more about the native heap, start with !heap -s and look up the other !heap commands.



          The .NET managed heap retains a type system. To analyze the managed heap, you need an extension for WinDbg called sos. Usually you load it by .loadby sos clr. It has a command !dumpheap -stat which may give you a first impression of its capabilities. (Run the command twice if you get an error message)



          This should give you enough hints to do further research and find more details in your crash dump.



          Strange?



          You seem to have 230 stacks with a total of 2.5 GB of memory. That is about 11 MB of memory per stack. Usually that's limited to 1 MB.



          Your updated example code



          I compiled the following program



          using System;
          using System.Runtime.InteropServices;
          namespace SO55043889

          class Program

          public static int[] arr;
          static IntPtr pointer;
          static void Main()

          const int GBSize = 1 * 1024 * 1024 * 1024/ sizeof(int);
          Console.WriteLine("Allocating");
          arr = new int[GBSize];
          pointer = Marshal.AllocHGlobal(1024 * 1024 * 1024 );
          Console.ReadLine();
          Console.WriteLine(pointer.ToInt32() + arr[0]);





          I ran the application and I attached to the process with WinDbg. I took a dump using



          0:000> .dump /ma SO55043889.dmp


          and now we can analyze it like this:



          0:000> !address -summary
          [...]
          <unknown> 106 474f4000 ( 1.114 GB) 51.58% 27.86%
          Heap 13 401e1000 ( 1.002 GB) 46.38% 25.05%
          [...]


          So we see 1 GB of (potentially) .NET memory and 1 GB of native memory.



          0:000> .loadby sos clr
          0:000> !dumpheap -stat
          c0000005 Exception in C:WindowsMicrosoft.NETFrameworkv4.0.30319sos.dumpheap debugger extension.
          PC: 04f6fa73 VA: 00000000 R/W: 0 Parameter: 00000000
          0:000> *** This is normal, just do it again
          0:000> !dumpheap -stat
          [...]
          70d20958 12 1073742400 System.Int32[]
          Total 335 objects


          There are 12 int[] on the .NET side, taking a total of ~1 GB from the managed heap. Looking at the details, we see that there's only one big array and some smaller ones:



          0:000> !dumpheap -type System.Int32[]
          Address MT Size
          020e1ff8 70d20958 300
          020e2130 70d20958 24
          020e2184 70d20958 40
          020e2228 70d20958 80
          020e2d9c 70d20958 16
          020e2dac 70d20958 16
          020e2df8 70d20958 16
          020e386c 70d20958 24
          020e3d54 70d20958 16
          020e3d64 70d20958 16
          020e3d74 70d20958 16
          04811010 70d20958 1073741836

          Statistics:
          MT Count TotalSize Class Name
          70d20958 12 1073742400 System.Int32[]
          Total 12 objects


          That's not what you wanted know. I just showed you how easy it is on the .NET side.



          Now the native side:



          0:004> !heap -s
          LFH Key : 0x7f8d0cc6
          Termination on corruption : ENABLED
          Heap Flags Reserv Commit Virt Free List UCR Virt Lock Fast
          (k) (k) (k) (k) length blocks cont. heap
          -----------------------------------------------------------------------------
          Virtual block: 80010000 - 80010000 (size 00000000)
          00550000 00000002 1024 504 1024 14 17 1 1 0 LFH
          002d0000 00001002 64 16 64 2 2 1 0 0
          00820000 00041002 256 4 256 2 1 1 0 0
          00750000 00001002 64 20 64 7 2 1 0 0
          00710000 00001002 256 4 256 0 1 1 0 0
          001e0000 00041002 256 4 256 2 1 1 0 0
          -----------------------------------------------------------------------------


          We can't see the 1 GB here. And there's a reason for that.



          As explained before, heap managers are good at dividing large blocks from VirtualAlloc() (which are 64kB) into smaller pieces. They do that because it would be a big waste to allocate 64kB just for a 4 byte int. However, there's no need to create heap management stucture for large blocks. For an allocation of 2^30+1 byte, the OS would return 2^30+64kB, which means the overhead is just 0.006%.



          That's why you will find allocations >512kB not inside the usual heap management structures but as a Virtual block, which means that the Windows Heap Manager has simply forwarded the request to VirtualAlloc().



          There's another issue here: the output for the size is broken. It says



          (size 00000000)


          which obviously is not true. Let's look at it ourselves:



          0:004> !address 80010000 
          Usage: Heap
          Base Address: 80010000
          End Address: c0011000
          Region Size: 40001000
          [...]

          0:004> ? c0011000-80010000
          Evaluate expression: 1073745920 = 40001000


          What we see here is that End Adress - Base Address equals the Region Size and the size is 1 GB.



          At this point, it's worth noting that the user mode stack trace database is useless. It only applies to items on the heap, but not VirtualAlloc(). You'll not figure out who allocated the 1 GB block.



          And I forgot to enable the user mode stack trace database anyway. Let's do that and cross check



          0:000> !gflag
          Current NtGlobalFlag contents: 0x00001000
          ust - Create user mode stack trace database


          And now, there should be stack traces for smaller pieces of memory. In this example, I use an arbitrary block of size 0x208:



          0:000> !heap -flt s 208
          _HEAP @ 2a0000
          HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
          002c9818 0044 0000 [00] 002c9830 00208 - (busy)
          002cd1e8 0044 0044 [00] 002cd200 00208 - (busy)
          002d5ad0 0044 0044 [00] 002d5ae8 00208 - (busy)
          002f0c48 0044 0044 [00] 002f0c60 00208 - (busy)
          0032c210 0044 0044 [00] 0032c228 00208 - (busy)
          00351c90 0044 0044 [00] 00351ca8 00208 - (busy)
          0:000> *** Use any UserPtr number, I use the last one
          0:000> !heap -p -a 00351ca8
          address 00351ca8 found in
          _HEAP @ 2a0000
          HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
          00351c90 0044 0000 [00] 00351ca8 00208 - (busy)
          779dd909 ntdll!RtlAllocateHeap+0x00000274
          71e18bc7 clr!EEHeapAlloc+0x0000002c
          71e18c0a clr!EEHeapAllocInProcessHeap+0x0000005b
          71e18ba6 clr!ClrAllocInProcessHeap+0x00000023
          71e2dd26 clr!StackingAllocator::AllocNewBlockForBytes+0x00000082
          71e2dd76 clr!operator new+0x00000063
          71e93ace clr!MethodTableBuilder::BuildMethodTableThrowing+0x00000059
          71e94590 clr!ClassLoader::CreateTypeHandleForTypeDefThrowing+0x0000083a
          71e2e956 clr!ClassLoader::CreateTypeHandleForTypeKey+0x000000ad
          71e2e99a clr!ClassLoader::DoIncrementalLoad+0x000000c2
          71e2e418 clr!ClassLoader::LoadTypeHandleForTypeKey_Body+0x00000505
          71e2e5a7 clr!ClassLoader::LoadTypeHandleForTypeKey+0x000000b5
          71e2f723 clr!ClassLoader::LoadTypeDefThrowing+0x00000318
          71e2a974 clr!ClassLoader::LoadTypeDefOrRefThrowing+0x0000024c
          71f57811 clr!Assembly::GetEntryPoint+0x0000022f
          71f856e0 clr!Assembly::ExecuteMainMethod+0x000000b3
          71f855ed clr!SystemDomain::ExecuteMainMethod+0x00000631
          71f858d3 clr!ExecuteEXE+0x0000004c
          71f85819 clr!_CorExeMainInternal+0x000000dc
          71f55a0c clr!_CorExeMain+0x0000004d
          7251d93b mscoreei!_CorExeMain+0x0000010e
          72597f16 MSCOREE!ShellShim__CorExeMain+0x00000099
          72594de3 MSCOREE!_CorExeMain_Exported+0x00000008
          77999802 ntdll!__RtlUserThreadStart+0x00000070
          779997d5 ntdll!_RtlUserThreadStart+0x0000001b


          Just one more note: if you modify the program to have smaller blocks of memory, e.g.



          for (int i = 0; i < 1000; i++)

          pointer = Marshal.AllocHGlobal(3*1024 );



          You will see the allocation in the heap:



          0:004> ? 3*0n1024
          Evaluate expression: 3072 = 00000c00
          0:004> !heap -flt c00
          cound not parse flt criteria -flt c00
          0:004> !heap -flt s c00
          _HEAP @ 67c0000
          HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
          0686b668 0183 0000 [00] 0686b680 00c00 - (busy)
          0686efa8 0183 0183 [00] 0686efc0 00c00 - (busy)
          [...]


          And you will see stack traces



          0:004> !heap -p -a 4d0fdf18 
          address 4d0fdf18 found in
          _HEAP @ 67c0000
          HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
          4d0fdf00 0191 0000 [00] 4d0fdf18 00c00 - (busy)
          779dd909 ntdll!RtlAllocateHeap+0x00000274
          768f5aae KERNELBASE!LocalAlloc+0x0000005f
          70c6ad4f mscorlib_ni+0x003fad4f
          7138c4da mscorlib_ni+0x00b1c4da
          71e0ebb6 clr!CallDescrWorkerInternal+0x00000034
          71e11e10 clr!CallDescrWorkerWithHandler+0x0000006b
          71e17994 clr!MethodDescCallSite::CallTargetWorker+0x0000016a
          71f85026 clr!RunMain+0x000001ad
          71f85707 clr!Assembly::ExecuteMainMethod+0x00000124
          [...]


          But you won't see the managed method calls. That's because the USt database was built for native only. It's the same reason you have different stacks in .NET using k or !dumpstack.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Mar 9 at 14:26

























          answered Mar 8 at 16:45









          Thomas WellerThomas Weller

          29.2k1169141




          29.2k1169141












          • I added sample code, your answer absolutely correct, if we don't know what is in <Heap> , it is just bytes. But in real word we always have some DLL(s) referenced, and code which allocate Unmanaged memory, It is just very hard to identify this DLL(s) and code. And this is what I am looking for. Find who allocated 1GB code in sample.( or 14 Gb in first example)

            – justromagod
            Mar 8 at 17:32












          • So it works! I am eager waiting to check it real life. Thank you a lot!

            – justromagod
            Mar 9 at 14:26











          • @justromagod: I just added another note regarding the NET stack

            – Thomas Weller
            Mar 9 at 14:26











          • it seems without gflag enabled, all my dumps are useless.

            – justromagod
            Mar 11 at 14:34











          • @justromagod: yes

            – Thomas Weller
            Mar 11 at 14:42

















          • I added sample code, your answer absolutely correct, if we don't know what is in <Heap> , it is just bytes. But in real word we always have some DLL(s) referenced, and code which allocate Unmanaged memory, It is just very hard to identify this DLL(s) and code. And this is what I am looking for. Find who allocated 1GB code in sample.( or 14 Gb in first example)

            – justromagod
            Mar 8 at 17:32












          • So it works! I am eager waiting to check it real life. Thank you a lot!

            – justromagod
            Mar 9 at 14:26











          • @justromagod: I just added another note regarding the NET stack

            – Thomas Weller
            Mar 9 at 14:26











          • it seems without gflag enabled, all my dumps are useless.

            – justromagod
            Mar 11 at 14:34











          • @justromagod: yes

            – Thomas Weller
            Mar 11 at 14:42
















          I added sample code, your answer absolutely correct, if we don't know what is in <Heap> , it is just bytes. But in real word we always have some DLL(s) referenced, and code which allocate Unmanaged memory, It is just very hard to identify this DLL(s) and code. And this is what I am looking for. Find who allocated 1GB code in sample.( or 14 Gb in first example)

          – justromagod
          Mar 8 at 17:32






          I added sample code, your answer absolutely correct, if we don't know what is in <Heap> , it is just bytes. But in real word we always have some DLL(s) referenced, and code which allocate Unmanaged memory, It is just very hard to identify this DLL(s) and code. And this is what I am looking for. Find who allocated 1GB code in sample.( or 14 Gb in first example)

          – justromagod
          Mar 8 at 17:32














          So it works! I am eager waiting to check it real life. Thank you a lot!

          – justromagod
          Mar 9 at 14:26





          So it works! I am eager waiting to check it real life. Thank you a lot!

          – justromagod
          Mar 9 at 14:26













          @justromagod: I just added another note regarding the NET stack

          – Thomas Weller
          Mar 9 at 14:26





          @justromagod: I just added another note regarding the NET stack

          – Thomas Weller
          Mar 9 at 14:26













          it seems without gflag enabled, all my dumps are useless.

          – justromagod
          Mar 11 at 14:34





          it seems without gflag enabled, all my dumps are useless.

          – justromagod
          Mar 11 at 14:34













          @justromagod: yes

          – Thomas Weller
          Mar 11 at 14:42





          @justromagod: yes

          – Thomas Weller
          Mar 11 at 14:42



















          draft saved

          draft discarded
















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid


          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.

          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55043889%2fhow-to-find-what-is-in-unmanaged-memory-in-dump-by-windbg%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          AWS Lex not identifying response if by a variable The 2019 Stack Overflow Developer Survey Results Are In Announcing the arrival of Valued Associate #679: Cesar Manara Planned maintenance scheduled April 17/18, 2019 at 00:00UTC (8:00pm US/Eastern) The Ask Question Wizard is Live! Data science time! April 2019 and salary with experienceEnforcing custom enumeration in AWS LEX for slot valuesHow to give response based on user response in Amazon Lex?Intercepting AWS Lambda Response to a AWS Lex QueryLex chat bot error: Reached second execution of fulfillment lambda on the same utteranceamazon lex showing invalid responseLambda response send back to Lex slot?Response card in Amazon lexAmazon Lex - Lambda response return HTML to botHow can I solve 424 (Failed Dependency) (python) obtained from Amazon lex?

          Алба-Юлія

          Захаров Федір Захарович