why does "UInt64[] arr=new UInt64[UInt64.MaxValue];" throw exception? - c#

Why does following code throw exception "Arithmetic operation resulted in an overflow." ?
UInt64[] arr=new UInt64[UInt64.MaxValue];

I guess because totally 8 * UInt64.MaxValue bytes is requested to be allocated, and this multiplication obviously overflows a 64-bit register.

Because indexers only take Int32 values. You can do
UInt64[] arr=new UInt64[Int32.MaxValue];
But thats the limit.
EDIT: Technically you can index an array with value structures that can theoretically be higher than Int32.MaxValue (because you can index an array with a long or a uint for example), however, you will run into that runtime error when the value exceeds Int32.MaxValue.

Because
a) all object are limited to 2GB in .NET
b) You don't have 64 PetaBytes of memory to spend

According to Microsoft's documentation, with framework .NET 4.5 these limitations apply:
The maximum number of elements in an array is UInt32.MaxValue.
The maximum index in any single dimension is 2,147,483,591 (0x7FFFFFC7) for byte arrays and arrays of single-byte structures, and 2,146,435,071 (0X7FEFFFFF) for other types.
The maximum size for strings and other non-array objects is unchanged

Related

Why is Max size of int array lower than Int32.MaxValue? [duplicate]

This question already has answers here:
Can't create huge arrays
(2 answers)
What is the maximum length of an array in .NET on 64-bit Windows
(3 answers)
Closed 1 year ago.
Even though this post says it should work, if you create an int array of size Int32.MaxValue, it throws an OutOfMemoryException: Array dimensions exceeded supported range.
From my testing, it seems like the maximum size that an array can be initialized to is Int32.MaxValue - 1048576 (2,146,435,071). 1048576 is 2^20. So only this works:
var maxSizeOfIntArray = Int32.MaxValue - 1048576;
var array = new int[maxSizeOfIntArray];
Does any one know why? Is there a way to create a larger integer array?
PS: I need to use arrays instead of lists because of a Math.Net library that only returns arrays for sets of random numbers that are cryptographically secure pseudo random number generator
Yes I have looked at the other questions linked but they are not correct as those questions say the largest size is Int32.MaxValue which is not the same as what my computer lets me do
Yes, I do know the size of the array will be 8GB, I need to generate a data set of billions of rows in order to test the randomness with the die harder suite of tests
I also tried the option of creating a BigArray<T> but that doesn't seem to be supported in C# anymore. I found one implementation of it, but that throws an IndexOutOfRangeException at index 524287, even though I set the array size to 3 million.
An Int32 is 32 bits, or 4 bytes. The max value of an Int32 is 2,147,483,647. So, if you could create an array of 2,147,483,647 elements, where each element is 4 bytes, you would need a contiguous piece of memory that is 8GB in size. That is ridiculously huge, and even if your machine had 128GB of RAM (and you were running in a 64-bit process), that would be outside of realistic proportions. If you really need to use that much memory (and your system has it), I would recommend going to native code (i.e., C++).

Error when Dictionary count is bigger as 89478457

I am getting on this command
Dictionary<UInt64, int> myIntDict = new Dictionary<UInt64, int>(89478458);
this error:
System.OutOfMemoryException was unhandled HResult=-2147024882
Message=Array dimensions exceeded supported range.
Source=mscorlib
StackTrace:
at System.Collections.Generic.Dictionary`2.Initialize(Int32 capacity)
at System.Collections.Generic.Dictionary`2..ctor(Int32 capacity, IEqualityComparer`1 comparer)
On 89478457 there is no error. Here is the source of Initialize in Dictionary.cs:
private void Initialize(int capacity)
{
int size = HashHelpers.GetPrime(capacity);
...
entries = new Entry[size];
...
}
When I reproduce this, the error happens on the array creation. Entry is a struct in this case with size 24. When we get max int32 (0x80000000-1) and divide on 24 = 89478485 and this number is between prime numbers 89478457 and 89478503.
Does this mean, that array of struct cannot be bigger as maxInt32/sizeOfThisStruct?
EDIT:
Yes. I actually go over 2 GB. This happens, when the dictionary creates the internal array of struct Entry, where are the (key,value) pairs stored. In my case the sizeof(Entry) is 24 bytes and as value type is inline allocated.
And the solution is to use the gcAllowVeryLargeObjects flag (thank you Evk). Actually in .net core the flag is the environment variable COMPlus_gcAllowVeryLargeObjects (thank you svick).
And yes, Paparazzi is right. I have to think about, how not to waste memory.
Thank you all.
There is known limitation of .NET runtime - maximum object size allowed on the heap is 2 GB, even on 64-bit version of runtime. But, starting from .NET 4.5 there is configuration option which allows you to relax this limit (only on 64-bit version of runtime still) and create larger arrays. Example of configuration to enable that is:
<configuration>
<runtime>
<gcAllowVeryLargeObjects enabled="true" />
</runtime>
</configuration>
On the surface Dictionary does not make sense
You can only have int unique values
Do you really have that my duplicates
UnInt32 goes to 4,294,967,295
Why are you wasting 4 bytes?
89,478,458 rows
Currently a row is 12 bytes
You have 1 GB at about 83,333,333 rows
Since an object needs contiguous memory 1 GB is more of a practical limit
If values is really a strut 24
Then 1 gb in 31,250,000
That is just a really big collection
You can split is up into more than one collection
Or use a class as then it is just a reference with I think is 4 bytes

.Length behavior vs .LongLength when array size is larger than Int32.MaxValue

I'm looking for some documentation on the differences between an array's .Length and .LongLength properties.
Specifically, if the array's length is larger than Int32.MaxValue, will .Length throw an exception, return Int32.MaxValue, go negative, return 0?
(to clear up "possible duplicate" concerns: I'm not asking about the maximum length of an array, or the maximum size of a .NET CLR object. Assume a 64 bit system and a CLR version which supports large objects)
It is not possible to create a one dimensional array having more than 2,147,483,591 elements (for comparison, int.MaxValue is 2,147,483,647). OutOfMemoryException is thrown if an attempt is made to create an array with more elements. It means that the LongLength property is still useless and you can use the Length property instead.
I've tested it on the x64 platform using .NET 4.5. In order to create the array with 2,147,483,591 elements I've modified the configuration file and added:
<configuration>
<runtime>
<gcAllowVeryLargeObjects enabled="true" />
</runtime>
</configuration>
Basically, I used this MSDN page to enable arrays that are greater than 2 (GB) in total size. The real limit for arrays:
The maximum index in any single dimension is 2,147,483,591
(0x7FFFFFC7) for byte arrays and arrays of single-byte structures, and
2,146,435,071 (0X7FEFFFFF) for other types.

System memory exception on for loop

I have the following code below:
List<long> numbers = new List<long>();
for (long i = 1; i <= 300000000; i++)
{
numbers.Add(i);
}
What I wanted to do is to populate the list from 1-300 million. But when it hit the 67108865, it throws an exception on line 4: Exception of type 'System.OutOfMemoryException' was thrown.
I tried using ulong but still no luck.
I believe the maximum range for long data type is 9,223,372,036,854,775,807 but why am I having an error here?
Thanks in advance!
EDIT
Thanks for all the answers. It helped my realized that my design is not good. I ended up changing my code design.
Well, it is not that your number are to large, but your list is...
Lets calculate it's size:
300,000,000 * 64 bits (size of long) = 19,200,000,000 bits
19,200,000,000 /8 (size of byte) = 2,400,000,000
2,400,000,000 / 2^10 = 2,343,750 KB
2,343,750 / 2^10 = 2,288~ MB
2,288/ 2^10 = 2.235~ GB
You wanted a list of about 2.35 GB.
The current CLR limitation is 2 GB (see this or this SO thread)
If you need a list with size of 300,000,000, split it into 2 lists (either in place or using a wrapping object that will handle managing the lists).
First note System.OutOfMemoryException is not thrown when limit is reached for a variable,
Secondly, it is thrown because there is not enough memory available to continue the execution of a program.
Sadly you can not configure, .the NET runtime makes all the decisions about heap size and memory.
Either switch to 64-bit machine.
For info, on 32 bit machine you can increase the memory by using /3GB boot switch option in Boot.ini
EDIT While searching I found in MSDN Documentation under Remarks section
By default, the maximum size of an Array is 2 gigabytes (GB). In a 64-bit environment, you can avoid the size restriction by setting the enabled attribute of the gcAllowVeryLargeObjects configuration element to true in the run-time environment. However, the array will still be limited to a total of 4 billion elements, and to a maximum index of 0X7FEFFFFF in any given dimension (0X7FFFFFC7 for byte arrays and arrays of single-byte structures).
A List<long> is backed by an long[]. You will fail as soon as the backing array cannot be allocated, during the reallocation, there has to be enough total memory for both the old and the new arrays.
But, if you want a collection with more than 231 elements, you have to write your own implementation by using multiple arrays or List, and managing them.
Your numbers are not too large; your list is too long. It is using all the available memory.
Reduce 300000000 to 3000000, and it will (probably) work fine.
It should ideally hold number of elements that you are telling.
But, as per current CLR implementation each object can have max 2 GB size. As you are storing long values (size 8 bytes), then while populating the List, it is somewhere trying to exceed the 2GB limit. That's why you are getting System.OutOfMemoryException

what is the exact maximum limit of elements in an array

This is a purelly theoretical question, so please do not warn me of that in your answers.
If I am not mistaken, and since every array in .NET is indexed by an Int32, meaning the index ranges from 0 to Int32.MaxValue.
Supposing no memory/GC constraints are involved an array in .NET can have up to 2147483648 (and not 2147483647) elements. Right?
Well, in theory that's true. In fact, in theory there could be support for larger arrays - see this Array.CreateInstance signature which takes long values for the lengths. You wouldn't be able to index such an array using the C# indexers, but you could use GetValue(long).
However, in practical terms, I don't believe any implementation supports such huge arrays. The CLR has a per-object limit a bit short of 2GB, so even a byte array can't actually have 2147483648 elements. A bit of experimentation shows that on my box, the largest array you can create is new byte[2147483591]. (That's on the 64 bit .NET CLR; the version of Mono I've got installed chokes on that.)
EDIT: Just looking at the CLI spec, it specifies that arrays have a lower bound and upper bound of an Int32. That would mean upper bounds over Int32.MaxValue are prohibited even though they can be expressed with the Array.CreateInstance calls. However, it also means it's permissable to have an array with bounds Int32.MinValue...Int.MaxValue, i.e. 4294967296 elements in total.
EDIT: Looking again, ECMA 335 partition III section 4.20 (newarr) specifies that a initializing a vector type with newarr has to take either a native int or int32 value. So it looks like while the normally-more-lenient "array" type in CLI terminology has to have int32 bounds, a "vector" type doesn't.

Categories

Resources