Heap size in C# / .Net Framework - Can it grow and

2019-07-07 04:02发布

问题:

This question already has an answer here:

  • Can I (and do I ever want to) set the maximum heap size in .net? 4 answers

I've encounterd a confusing matter written in one of my college books: It is stated there that "The heap is not static and can grow as needed by requesting more memory from the operating system".

So what I'm confused about is the following: Suppose I run my application, and objects are allocated on the heap. At some point, the application runs out of memory: what happens now?

From what I understand, Gc (Garbage collector) kicks in and begins it's mark and sweep operations. I wonder if somehow, instead of invoking the Gc by the CLR, is there any possibility for the heap to request more memory from the operating system?

I read that in C++ language, there is a way to achieve that, but is it possible in C# .Net Framework 4.5?

回答1:

The heap in .Net is a portion of memory that for practical purposes can reach a maximum of around 1.5GB for 32-bit processes and unlimited for 64-bit (again, for practical purposes), and it will indeed request memory as needed from the OS. However it may run out of memory due to excessive fragmentation and use of large allocations - the GC won't compact the large object heap.

When you do it in C++ you have total control on how you want to strategize memory allocation, in .NET that is done for you, and you have very little say on how that is done even though for the most part it does a damn good job.



回答2:

It's important to realize that an "out of memory" error doesn't mean you're out of physical memory. It means you're out of virtual memory. In a 32 bit application there are 2^32 possible addresses for an item in that applications virtual address space.

The operating system is responsible for mapping sections of that virtual address space to actual physical storage media, whether that be RAM, the hard drive, or any other storage device. Since most applications aren't using the vast majority of their virtual address space, most of it is mapped to nothing, and doesn't correspond to anything until they first begin to use it.

While it is possible for a program to change, as it goes, what blocks of virtual memory correspond to actual blocks of physical memory (which is required for a program to utilize more than 2^32 words of memory at once) doing so is uncommon, usually only done by programs such as video processing applications that really do need to store lots of memory all at once. This process is also manual. if you aren't manually swapping out what each block of virtual memory maps to you can run out of virtual memory, even if you still have storage devices capable of storing more information. That's an Out of Memory error.

The heap, in a C# application, is pretty much the entirety of the virtual address space that's not taken up by the stack, the storage of static fields, and any other overhead such as the memory for the actual code of the program. From the application's perspective, the heap is as big as it ever gets right from the start. The OS has abstracted away the fact that virtually all of what the C# runtime thinks of as "it's memory" doesn't actually map anywhere, because it's not used; as you start to use more of the heap, more and more of it actually gets mapped to some form of physical storage.

If you have a 64 bit application you can basically replace all instances of 32 with 64 in this answer.



回答3:

A heap is dynamic in the sense that when you add to the heap, it grows. It creates pointers in a sense to other locations in memory. There is always a limit to a size of memory an application can take until it runs out of memory. When the limit is reached, you will generally get an "out of memory" exception.

Read the wiki might help:
http://en.wikipedia.org/wiki/Heap_%28data_structure%29
http://en.wikipedia.org/wiki/Heap_%28programming%29#Dynamic_memory_allocation



回答4:

The heap grows because your application is allocating and holding on to objects. Heap requests memory whenever your application needs to store pointers to objects, which are currently in use by your application.

Whenever you ran out of heap, you'll receive error prompting that heap memory unavailable or something like that. To avoid such GC is provided and you can control this behaviour if you implement your own CLR-host. please Refer

There are a couple of things you can do to limit the memory usage. Please see this question for some input: Reducing Memory usage

To know more about heap(ing) as well as stack(ing) please refer follwoing links:

  1. Stack and heap
  2. Large Object Heap Uncovered
  3. Fundamentals of Garbage Collection


回答5:

You can allocate MUCH MORE memory than ~2 GB by building your application to a 64-bit architecture, which requires that you create a new build configuration. Using the normal (default) "Any CPU" build option for your .NET project, your application will ALWAYS run under 32-bit mode, even on a 64-bit Windows OS. Therefore you won't be able to allocate more than about 1.5 to 2 GB of RAM memory during application execution. To run your .NET application in true 64-bit mode, you will need to go into the build configuration manager and create a build type for the x64 architecture, and then recompile your program for x64 explicitly using that build type. The x64 build mode option can be created for your .NET solution using the following steps:

  1. In the Visual Studio "Solution Explorer" pane, right click on the Solution icon and choose the "Configuration Manager" option from the pop-up menu. This will open the build "Configuration Manager" dialog window for the .NET Solution file.
  2. On the right, top side of the build "Configuration Manager" dialog, click on the down arrow and select the "<new>" option. This will open the "New Solution Platform" dialog.
  3. In the "New Solution Platform" dialog, for the "Platform" option, choose "x64" from the drop-down menu. Then click the "OK" button and the new, x64 build option will now be available in the Configuration Manager dialog.
  4. Then, on the "Configuration Manager" dialog, select "x64" in the "Active Solution Platform" drop-down menu. The click the "Close" button.
  5. In the Visual Studio "Solution Explorer" pane, right click on the CS Project icon and choose the "Properties" option from the pop-up menu (the last option at the bottom of this menu). This will open the CS Project properties window.
  6. On left side of the CS Project properties window, click on the "Build" tab to show the build properties for your code project. At the top of this window, notice that the "Platform" should now say "x64" (as opposed to the default "Any CPU" option). If the "Platform" drop-down doesn't show "x64", you should select it now.
  7. Then just build your code and in the "bin" folder, you should now have a x64 folder with the new 64-bit build of your application within it.

Using a 64-bit build of your application on a 64-bit Windows OS will allow your program to allocate much more than ~2GB of memory, presumably up to 2^64 address spaces (if you have the RAM and disk space available, which are the real limiting factors as of the time of writing this response).

If you're STILL running out of memory in your application, you can also increase the size of the Windows memory page file. On Windows, the page file allows the operating system to shift memory from RAM to the disk, if it runs out of RAM memory space. But there is a big time cost in shifting sections of RAM memory to and from the disk, so it may be a real hit on the performance of your application. Regardless of performance, by increasing the page size, you could (in theory) make the page file as large as there is free space available on the C: drive of your windows machine. In that case, your application would be able to allocate, for example, up to 4 TB of memory (or whatever amount of memory that your page file size is set to) during the execution of your program. To change the page file settings for your Windows machine, do the following:

  1. Open the "System Properties" dialog by right clicking on "This PC" and choosing the "Properties" option on the pop-up menu. This can also be accomplished in later versions of Windows (Windows 10, Win 2012 Server, etc...) by going to "Start" > "Control Panel" > "System and Security" > "System".
  2. On the left side of the "System" dialog, click on the "Advanced System Properties" option. This will show the "Advanced" tab of the legacy "System Properties" dialog for Windows.
  3. On the "Advanced" tab of the legacy "System Properties" dialog, click the "Settings" button in the "Performance" box. This will option the "Performance Options" dialog.
  4. On the "Performance Options" dialog, click on the "Advanced" tab to see the current size setting for the Windows memory page file.
  5. To increase the page file size, click on the "Change" button and the "Virtual Memory" dialog will be opened.
  6. On the "Virtual Memory" dialog, select the "C:" drive, then under "Custom Size", set the "Initial" and "Maximum" sizes. You can use any size up to the maximum amount of free space on the C: drive, but making this change will reserve that space for the page file on the hard drive.
  7. Then click "Ok" on all dialogs to commit the new settings. Then reboot your computer to ensure all changes have been completed properly and that the new page file settings are in operation.

Anyway, I hope this helps people understand why they can run into this 1.5 - 2 GB memory limitation issue in a .NET application, even when running on a 64-bit Windows machine. This can be a very confusing issue for people and I hope my explanation makes sense. Please feel free to message me with questions about this answer if needed.