4

For example: I have a struct named Item

#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub struct Item {
  ...fields
}

and I am storing those items inside a PDA account named UserAccount

#[account]
pub struct UserAccount {
    pub owner: Pubkey,              
    pub items: Vec<Item>,
}

At the account initialization i am setting the account size to MAX_PERMITTED_DATA_INCREASE that means 10240 bytes.At this stage i am able store almost 115 items into the vector without any issue.

I have some logic in place that reallocates another 10240 bytes when there is not enough space to store another item. This part also works fine. At this stage account size is 20480 bytes.

After allocating the space second time,and when try to push new item, i get Program log: Error: memory allocation failed, out of memory. This error doesn't happen after immediate allocation. From my testing it looks like it throws this error randomly, sometimes i am able to push abother 10 items (125 total), some times 20(145 toal) items and after that it gives me this error. This happends after adding few items.

From few other threads i came to know push method allocates the entire account's state, I am not sure what does that mean. If i am within the limit why that would be an issue.

So my question is why this error actually happening , even i have enough space for vector to grow and I think i am within the boundary of heap limit. What actually going on under the hood ?

Edit: Here is the repository demonstrating the issue: https://github.com/Imran-S-heikh/solana-memory-issue

Any Kind of help is really appreciated.

5
  • Can you share your original code? using push to add additional items in a vector shouldn't be the problem. The problem must be somewhere else.
    – 0xShuk
    Commented Apr 20, 2023 at 18:56
  • As the original code in private repo , i won't be able to do it. But i will recreate the issue in a seperate repo. Commented Apr 21, 2023 at 22:49
  • Imran: So did you resolve this issue? If so, how exactly? BTW, did you face this issue locally with solana-test-validator, or devnet or mainnet? Commented Jun 9, 2023 at 18:17
  • I've almost same situation.. My account has Vec<Pubkey> and one Pubkey member .. that's it. Initially, I allocate space for the vector for 318 Pubkeys... then I realloc 10240 once .. then I'm able to add pubkeys.. and till vec.len() <= 512, it works fine. But at 513 insertion, it fails with this error Error: memory allocation failed, out of memory. Commented Jun 9, 2023 at 18:25
  • @0xShuk Here is the repo i created for demonstrate the issue : github.com/Imran-S-heikh/solana-memory-issue Commented Sep 8, 2023 at 10:26

1 Answer 1

1

You are running out of memory (heap space) not account space.

After you run the test, check the account (userInfoAddress in your test) with this command solana account %account_pubkey% (local validator must be running) and you will see that the account bytes returned have a lot of unused space (the padding 0s at the end). So there is still space left in the account.

        ...

77c0:   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00   ................
77d0:   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00   ................
77e0:   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00   ................
77f0:   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00   ................

I have run your test and consistently get 496 friends added, I cannot reproduce the situation where "it throws this error randomly", so my answer is based on my results where the behavior is consistent. Although it still runs out of memory faster than you would expect.

Why it's running out of memory is because when you use Vec<T>.push(), it will reallocate memory in a way that is best suited and performant for most use-cases, and since memory reallocation is expensive it often just doubles the memory needed by the Vec<T> just so that it will not have to do a new reallocation too soon. So often your Vec<T> that by your calculations is, say, 100 bytes, will actually take up up to 200 bytes of memory.

So given that Vec<Friend> is 33 bytes * number of friends, the program in my case consistently fails after it added 496 friends. At 496 friends it represents 16368 bytes. At the next .push() it will try to double the Vec size which would now be 32kb+ bytes.

Given that Solana programs are limited to heap size of max 32kb, our Vec<Friends> + other variables in memory easily go over this limit and an error is thrown.

You can see these changes in memory allocation if you add this code to pub fn add_friend() after the .push()

let capacity = ctx.accounts.user_info.friends.capacity();
let size_of_friend = std::mem::size_of::<Friend>();
msg!("Capacity: {}, Size Of Friend: {}, Size: {}", capacity, size_of_friend, capacity * size_of_friend);

Notice how capacity of the Vec changes, with doubling often when it reallocates memory. These are the logs from my local machine.

There are different ways of manually allocating memory for a Vec in Rust, such as Vec::reserve().

PS: I appreciate you adding the git link to reproduce this error.

3
  • Thanks for your reply. Maybe I am missing something or just lack of knowledge around this. How Heap size differs from the account size we are calculating in anchor, let's say we added 100 friends, after adding 100 friends account size should be 3300 + 45 = 3345, but when we are getting size with ...%account_pubkey% | jq -c | wc -c command its returning 6873. Isn't it should be the same when loaded on heap or Why is the huge difference ? Sorry if my questions are silly. Commented Sep 9, 2023 at 6:18
  • 1
    My ...%account_pubkey% | jq -c | wc -c example was a very rough estimate of what a deserialized account looks like in memory, but I see you're looking for a more exact answer. My initial answer was meant to show that your problem is heap space not account space. Updated my answer to include why heap memory runs out faster than expected.
    – Serban
    Commented Sep 9, 2023 at 10:32
  • 1
    Exactly what i was looking for, I was confused why its not working as expected. Thank you for your help and effort. Commented Sep 9, 2023 at 11:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.