Skip to content

Would it be possible to resize arrays without reallocating? #8140

@svick

Description

@svick

Currently, when a type like List<T> wants to resize an array, it has to allocate a new array and copy all the elements from the old array to the new one (possibly using Array.Resize()). I think this copying can take a fairly long time, especially for large arrays.

But considering that on 64-bit platforms, there should be enough free virtual address space, would it be possible to "reserve" more address space for such growing arrays, so that they can be grown in place?

The way I imagine it could work is something like this:

  • There would be a new type ResizableArray<T>*, which would mostly behave just like an array, except that its Length can change and that its Resize method (public static void Resize(ref ResizableArray<T> array, int minNewSize)) either allocates a new ResizableArray<T> or changes its Length (see below). It has to be a new type, because nobody expects that the Length of T[] can change.
  • If ResizableArray<T>.Resize was called with a small minNewSize, it would behave similarly to Array.Resize and reallocate.
  • If called with a sufficiently large minNewSize on a small ResizableArray<T> (the limit could be the same as for LOH, or larger, depending on how fast reallocating an array is and how much wasting of virtual address space is acceptable), the array would be reallocated into a special area of memory, reserving its maximum size for it (AFAIK 232 · element size) in the virtual address space, but actually allocating only as much physical memory as requested. This would make it a "large" ResizableArray<T>.
  • If called on a large ResizableArray<T>, it would just allocate the new memory, without copying anything, since the virtual address space is available.
  • If virtual address space ran out because of too many resizable arrays (e.g. more than ~16k resizable int arrays on architectures with 48-bit address space like x64), part of the reserved address space for some resizable array could be reused. Calling Resize on that array could then potentially reallocate it.
  • Since ResizableArray<T>.Resize would actually allocate physical memory from the OS by pages, it could resize the array to more than what was asked for, which would mean no physical memory would be wasted (that's why the parameter is called minNewSize).
  • Just like normal array, ResizableArray<T> could be converted to Span<T>, which means there would be a common abstraction.

My questions:

  • Would this be possible?
  • Could this actually sufficiently increase performance?
  • Would the cost of making this work and adding the new type be warranted?
  • Are there better ways to solve this issue?

I think creating this type is primarily a matter of implementation, not API, which is why I'm opening this issue here, and not on corefx.


* This name is very similar to ResizeArray<T>, which is an F# alias for System.Collections.Generic.List<T>. So maybe a different name would be better?

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-System.RuntimeenhancementProduct code improvement that does NOT require public API changes/additionstenet-performancePerformance related issue

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions