How does the size limit of a single Sui Move object work

I want to understand how the size limit works in Sui move objects. I know that the size limit for a single object is 250kb. Let’s say I am creating an object of the type:

struct Table1 has key, store{
        id: UID,
        list: Table<String, bool>
    }

I create an object calling an init function from a move file:

fun init(ctx: &mut TxContext) { 
        let table_obj = Table1 {
                id: object::new(ctx),
                list: table::new(ctx)
        };
        transfer::public_transfer(channel_list, tx_context::sender(ctx));
   }

Now I keep adding new strings to the table calling this function:

public entry fun add_channel(
        table_obj: &mut Table1,
        elm: String
    ){
        table::add(&mut table_obj.list, elm, true);
    }

Let’s assume each unique string added to the table is of size 10 bytes so for each entry we add 11 bytes (including the boolean value), so the total values that can be added on the object would be 250000/11 ~ 22727 strings. Is there any gap in my understanding, or the upper limit of the data that can be added to the table would be higher (or lower)?

3 Likes

The Table collection type is storing both keys and values in dynamic fields Dynamic (Object) Fields | Sui Documentation, which do count against the size limit. So in your example, list can hold an unbounded number of objects, and you’ll never bump into the size limit!

The limit would come into play if you were using a collection type like vector, VecSet, or VecMap that stores collection elements directly rather than using dynamic fields.

4 Likes

Thanks! That clears up things.

1 Like

Hello Sir, I have a follow up question that according to the Move book:

It mentioned:

The maximum number of dynamic fields that can be created in a single object is 1024. If an object attempts to create more than 1024 dynamic fields, it will be rejected by the network.

Is that mean the table still has a size limit of 1024 entries, or I can create an object that holds 1024 tables, for example:

    public struct tables has key, store {
        id: UID,
        t1: table::Table<u64, u64>,
        t2: table::Table<u64, u64>,
        ....
        t1024: table::Table<u64, u64>,
    }

Good question! A few things

  • The 1024 limit applies to how many dynamic fields a single transaction can access. A Table itself has no size limit–you just can’t touch all its fields in one tx if it’s too big
  • You cannot put 1024 Tables in a single Move struct because there is a limit on the number of fields a struct can have (32). However, you could have 1024 dynamic fields, each of which holds a Table. I’d have a lot of questions about that design :slight_smile: , but it is possible
1 Like

Thank you so much sir. By the way, do we have a dedicated test environment to verify these limits?

I attempted using test_scenario to determine how many entries I could insert into a table, as shown below:

test_scenario::next_tx(scenario, user1);
{
    let mut ps = test_scenario::take_from_sender<Storage_test>(scenario);
    let mut i = 0;
    while i < 19999 {
        helpers::addEntry(i, i + 1, &mut ps); // Add one entry to the table
        i += 1;
    }
    test_scenario::return_to_sender(scenario, ps);
}

However, I encountered the following issue, which seems related to the VM’s internal limits and is little hard to debug:

2024-12-13T21:42:16.209137Z ERROR sui_move_natives_latest::dynamic_field: error=PartialVMError with status MEMORY_LIMIT_EXCEEDED with sub status 5 and message Object runtime cached objects limit (16000 entries) reached