What's the max items in a List<T>?

Learn what's the max items in a list? with practical examples, diagrams, and best practices. Covers c#, collections development techniques with visual explanations.

Understanding the Maximum Capacity of List in C#

Hero image for What's the max items in a List<T>?

Explore the theoretical and practical limits of List<T> in C#, including memory constraints, int maximum value, and how to handle large collections.

When working with collections in C#, List<T> is a fundamental and frequently used data structure. It provides a dynamic array that can grow or shrink as needed. A common question that arises, especially when dealing with large datasets, is: what is the maximum number of items a List<T> can hold? This article delves into the theoretical and practical limitations of List<T>, helping you understand its boundaries and how to manage scenarios requiring extremely large collections.

The Theoretical Limit: int.MaxValue

The capacity and count of a List<T> are internally managed using int data types. In C#, an int is a 32-bit signed integer, meaning its maximum possible value is 2,147,483,647. This value, int.MaxValue, represents the absolute theoretical upper bound for the number of elements a List<T> can contain. If you attempt to add an item that would cause the list's count to exceed int.MaxValue, an OutOfMemoryException or an OverflowException would typically occur before reaching this exact limit, due to memory constraints.

using System;
using System.Collections.Generic;

public class ListMaxCapacity
{
    public static void Main(string[] args)
    {
        Console.WriteLine($"Maximum value for int: {int.MaxValue}");
        // This is the theoretical maximum count for List<T>

        List<int> myList = new List<int>();
        // myList.Capacity and myList.Count are both int

        // Attempting to create a list with int.MaxValue capacity
        // List<object> largeList = new List<object>(int.MaxValue);
        // This line would likely throw an OutOfMemoryException on most systems
        // before even allocating the full capacity, as it would require
        // 2,147,483,647 * sizeof(reference) bytes of contiguous memory.
    }
}

Demonstrating int.MaxValue as the theoretical limit for List<T>.

The Practical Limit: Memory Constraints

While int.MaxValue is the theoretical ceiling, the practical limit for List<T> is almost always dictated by available memory. Each item in the list, whether it's a value type or a reference type, consumes memory. For value types (like int, double, structs), the actual data is stored directly in the list's underlying array. For reference types (like string, object, custom classes), the list stores references (pointers) to the objects, which are allocated on the heap.

Consider a List<object> on a 64-bit system. Each reference typically takes 8 bytes. If you tried to store int.MaxValue objects, you would need approximately 2.1 billion * 8 bytes = 17.179 billion bytes, or about 16 GB of contiguous memory just for the references, not including the objects themselves. This amount of contiguous memory is rarely available for a single allocation in a typical application, leading to an OutOfMemoryException long before int.MaxValue is reached.

flowchart TD
    A[Start Adding Items to List<T>] --> B{Is Current Count < int.MaxValue?}
    B -- Yes --> C{Is Enough Contiguous Memory Available?}
    C -- Yes --> D[Add Item Successfully]
    C -- No --> E[OutOfMemoryException]
    B -- No --> F[OverflowException / OutOfMemoryException]
    D --> A

Decision flow for adding items to a List<T> and encountering limits.

Impact of T (Type of Elements)

The actual memory footprint, and thus the practical limit, is heavily dependent on the type T of the elements stored in the list:

  • Value Types: If T is a value type (e.g., int, double, struct), the list stores the actual values directly. A List<long> will consume more memory per element than a List<byte>.
  • Reference Types: If T is a reference type (e.g., string, object, custom classes), the list stores references (pointers) to the objects. On a 64-bit system, each reference is typically 8 bytes. The actual objects themselves are stored on the heap and contribute significantly to the overall memory usage.

Even if the list itself could theoretically hold int.MaxValue references, the cumulative memory required for the referenced objects would almost certainly exhaust system resources much sooner.