Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What metric does AWS Lambda, specifically for Node.js runtime use to determine the Max Memory used?

I want to determine how large an array would be in memory for when my function executes. Determining the size of the array is easy but I am not seeing a correlation to the size of my array to the Max Memory used that gets recorded at the end of a Lambda execution.

There is no apparent coloration after inspecting process.memoryUsage() before and after setting the array as well as the Max Memory used reported by the Lambda. I can't find a good resource that indicates how/what Lambda actually uses to determine the memory used. Any help would be appreciated?

like image 550
DR. Avatar asked Oct 15 '25 13:10

DR.


2 Answers

This question made me curious myself, so I decided to run some tests to see how memory allocation works inside an AWS Lambda container.

Test 1: Create array with 100,000 elements in memory

Memory size: 128MB

exports.handler = async (event) => {
    const arr = [];
    for (let i = 0; i < 100000; i++) {
        arr.push(i);
    }
    console.log(process.memoryUsage());
    return 'done';
};

Result: 56 MB

2019-04-30T01:00:59.577Z    cd473d5b-986c-436e-8b36-b114410c84cf    { rss: 35299328,
  heapTotal: 11853824,
  heapUsed: 7590320,
  external: 8224 }
REPORT RequestId: 2a7548f9-5d2f-4060-8f9e-deb228730d8c  Duration: 155.74 ms Billed Duration: 200 ms     Memory Size: 128 MB Max Memory Used: 56 MB  

Test 2: Create array with 1,000,000 elements in memory

Memory size: 128MB

exports.handler = async (event) => {
    const arr = [];
    for (let i = 0; i < 1000000; i++) {
        arr.push(i);
    }
    console.log(process.memoryUsage());
    return 'done';
};

Result: 99 MB

2019-04-30T01:03:44.582Z    547a9de8-35f7-48e2-a53f-ab669b188f9a    { rss: 80093184,
  heapTotal: 55263232,
  heapUsed: 52951088,
  external: 8224 }
REPORT RequestId: 547a9de8-35f7-48e2-a53f-ab669b188f9a  Duration: 801.68 ms Billed Duration: 900 ms     Memory Size: 128 MB Max Memory Used: 99 MB  

Test 3: Create array with 10,000,000 elements in memory

Memory size: 128MB

exports.handler = async (event) => {
    const arr = [];
    for (let i = 0; i < 10000000; i++) {
        arr.push(i);
    }
    console.log(process.memoryUsage());
    return 'done';
};

Result: 128 MB

REPORT RequestId: f1df4f39-e0fc-4b44-8f90-c3c0e3d9c12d  Duration: 3001.33 ms    Billed Duration: 3000 ms    Memory Size: 128 MB Max Memory Used: 128 MB 
2019-04-30T00:54:32.970Z f1df4f39-e0fc-4b44-8f90-c3c0e3d9c12d Task timed out after 3.00 seconds

I think we can pretty confidently say that the memory used by the lambda container does go up based on the size of an array in memory; in our third test we ended up maxing out our memory and timing out. My assumption here is that the process that controls the execution of the lambda also monitors how much memory that execution acquires; likely by cat /proc/meminfo as trognanders suggests.

like image 176
Daniel Cottone Avatar answered Oct 18 '25 05:10

Daniel Cottone


Okay so I used the following code and increased the amount of array values to get a correlation. Three tests were done on each max value of the array. Lambda was set at 1024MB. Each array element is 10 chars/bytes long.

const util = require('util');
const exec = util.promisify(require('child_process').exec);


async function GetContainerUsage()
{
     const { stdout, stderr } = await exec('cat /proc/meminfo');
    // console.log(stdout);
    let memInfoSplits = stdout.split(/[\n: ]/).filter( val => val.trim());
    // console.log(memInfoSplits[19]); // This returns the "Active" value which seems to be used
    return Math.round(memInfoSplits[19] / 1024);
}


function GetMemoryUsage()
{
    const used = process.memoryUsage();

    for (let key in used)
        used[key] = Math.round((used[key] / 1024 / 1024));

    return used;
}

exports.handler = async (event, context) => 
{
    let max = event.ArrTotal;
    let arr = [];
    for(let i = 0; i < max; i++)
    {
        arr.push("1234567890"); //10 Bytes
    }

    let csvLine = [];
    let jsMemUsed = GetMemoryUsage(); 
    let containerMemUsed = await GetContainerUsage(); 


    csvLine.push(event.ArrTotal);
    csvLine.push(jsMemUsed.rss);
    csvLine.push(jsMemUsed.heapTotal);
    csvLine.push(jsMemUsed.heapUsed);
    csvLine.push(jsMemUsed.external);
    csvLine.push(containerMemUsed);  

    console.log(csvLine.join(','));
    return true;
};

This output the following values used in the CSV:

Array Count, JS rss, JS heapTotal, JS heapUsed, external, System Active, Lambda reported usage
1,30,7,5,0,53,54
1,31,7,5,0,53,55
1,30,8,5,0,53,55
1000,30,8,5,0,53,55
1000,30,8,5,0,53,55
1000,30,8,5,0,53,55
10000,30,8,5,0,53,55
10000,31,8,6,0,54,56
10000,33,7,5,0,54,57
100000,32,12,7,0,56,57
100000,34,11,8,0,57,59
100000,36,12,10,0,59,61
1000000,64,42,39,0,88,89
1000000,60,36,34,0,84,89
1000000,60,36,34,0,84,89
10000000,271,248,244,0,294,297
10000000,271,248,244,0,295,297
10000000,271,250,244,0,295,297

Which if graphed becomes: enter image description here

So at 10 Million elements the array is assumed to be 10mil*10bytes = 100MB. There must be some overhead I am missing somewhere as there is about 200MB used elsewhere. But at least there is a clear linear correlation, which I can now work with.

like image 45
DR. Avatar answered Oct 18 '25 06:10

DR.



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!