1

I mean is it really possible? MSDN says that arrays are fixed-size and the only way to resize is "copy-to-new-place". But maybe it is possible with unsafe/some magic with internal CLR structures, they all are written in C++ where we have a full memory control and can call realloc and so on.

I have no code provided for this question, because I don't even know if it can exist.


I'm not talking about Array.Resize methods and so on, because they obviosly do not have needed behaviour.

Assume that we have a standard x86 process with 2GB ram, and I have 1.9GB filled by single array. Then I want to release half of it. So I want to write something like:

MagicClass.ResizeArray(ref arr, n) 

And do not get OutOfMemoryException. Array.Resize will try to allocate another gigabyte of RAM and will fail with 1.9+1 > 2GB OutOfMemory.

3
  • you can declare an array like the following var someArray = {} then for example if you want to load it at runtime and do not know the potential size you could do something like this.. var someList = new List{"apple", "orange", "pears"}; then load the array like this someArray = someList.ToArray(); Commented Oct 29, 2015 at 16:10
  • 1
    Array.Resize(ref yourArray, newCount); Commented Oct 29, 2015 at 16:11
  • The problem is, you're not actually asking about a problem you have. This makes the question rather trivial, and the answers will likely miss your mark. Why would you want to truncate an array? In what kinds of situation do you want this, and what is the reason for trying to do an in-place truncation? Want to preserve every little byte of memory? Let the copy take place - that's what .NET is designed for. Want to avoid expensive copies while changing the size of the array? Use a list, and use it well - or even write your own, if it doesn't suit you. Commented Oct 29, 2015 at 16:30

3 Answers 3

2

You can try Array.Resize():

 int[] myArray = new int[] { 1, 2, 3, 4 }; int myNewSize = 1; Array.Resize(ref myArray, myNewSize); // Test: 1 Console.Write(myArray.Length); 
Sign up to request clarification or add additional context in comments.

2 Comments

That's still a copy - it's easily seen if you keep a copy of the original reference. Not that there's really a way to have it any other way, even in C++.
Array.Resize do not resize in-place.
1

realloc will attempt to do the inplace resize - but it reserves the right to copy the whole thing elsewhere and return a pointer that's completely different.

Pretty much the same outward behaviour is exposed by .NET's List<T> class - which you should be using anyway if you find yourself changing array sizes often. It hides the actual array reference from you so that the change is propagated throughout all of the references to the same list. As you remove items from the end, only the length of the list changes while the inner array stays the same - avoiding the copying.

It doesn't release the memory (you can always do that explicitly with Capacity = XXX, but that makes a new copy of the array), but then again, unless you're working with large arrays, neither does realloc - and if you're working with large arrays, yada, yada - we've been there :)

realloc doesn't really make sense in the kind of memory model .NET has anyway - the heap is continously collected and compacted over time. So if you're trying to use it to avoid the copies when just trimming an array, while also keeping memory usage low... don't bother. At the next heap compaction, the whole memory above your array is going to be moved to fill in the blanks. Even if it were possible to do the realloc, the only benefit you have over simply copying the array is that you would keep your array in the old-living heap - and that isn't necessarily what you want anyway.

Comments

1

Neither array type in BCL supports what you want. That being said - you can implement your own type that would support what you need. It can be backed by standard array, but would implement own Length and indexer properties, that would 'hide' portion of array from you.

public class MyTruncatableArray<T> { private T[] _array; private int _length; public MyTruncatableArray(int size) { _array = new T[size]; _length = size; } public T this[int index] { get { CheckIndex(index, _length); return _array[index]; } set { CheckIndex(index, _length); _array[index] = value; } } public int Length { get { return _length; } set { CheckIndex(value); _length = value; } } private void CheckIndex(int index) { this.CheckIndex(index, _array.Length); } private void CheckIndex(int index, int maxValue) { if (index < 0 || index > maxValue) { throw new ArgumentException("New array length must be positive and lower or equal to original size"); } } } 

It really depend what exactly do need. (E.g. do you need to truncate just so that you can easier use it from your code. Or is perf/GC/memory consumption a concern? If the latter is the case - did you perform any measurements that proves standard Array.Resize method unusable for your case?)

4 Comments

Array resize is just copying into another array. See example.
@Alex Zhukovskiy I'm not using Array.Resize anywhere in my code sample. Again - there is no standard BCL type supporting your need in the box. Based on your updated question - you have two options: 1) Allocate and manually manage non-managed memory (see Marshal.AllocHGlobal) and P/Invoke into C++ methods you mentioned (those methods still do not give you guarantee though). 2) Rewrite my simplified example to work with array of arrays and releasing//adding sub segments of memory based on requests
That's what I am talking about. It's bizzare to create another "memory managment" layer above the GC one, because it's the only cause to use .Net. I think that there is some way to hack internal CLR structures (EEClasses/Type references) to achieve expected result.
I see what you are saying. In that case your best bet is to investigate the CoreCLR sources yourself (github.com/dotnet/coreclr) and try to see how GC distinguishes length of occupied memory by array types. This is highly unsupported and highly likely to break in future (similar to tricks how to change or truncate strings in place - they work, but with different versions of .NET they can cause your code to blow up unexpectedly)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.