lowDb - недостаточно памяти - PullRequest
2 голосов
/ 16 мая 2019

У меня проблема с нехваткой памяти в Node.js, и я вижу много больших строк, которые невозможно собрать, когда я проверяю снимки кучи.

Я использую lowDB, и эти строки в основном являются содержимым файла lowDb.

Вопрос в принципе ...

Когда я использую FileAsync (поэтому запись в файл выполняется асинхронно), и я выполняю много записей (запускаю и забываю) ... возможно ли, что мое пространство кучи заполнено записями стека ожидания, которые все ожидают файловая система, чтобы закончить запись? (и узел может очистить память для каждой законченной записи).

Я делаю много записей, поскольку использую lowDB для сохранения сообщений журнала алгоритма, который я выполняю. Позже я хочу найти сообщения журнала определенного выполнения. Итак, в основном:

{ 
  executions: [
    {
      id: 1,
      logEvents: [...]
    },
    {
      id: 2,
      logEvents: [...]
    },
    ...       
  ]
}

Моя упрощенная картина обработки узла это:

  • мой скрипт - следующий скрипт в стеке и запускается
  • при каждой записи что-то ожидает, пока файловая система вернет ответ
  • это что-то раздувает мою память, и каждое из этих "чего-то" содержит весь контент файла lowdb (несколько раз?!)

Пример машинописного кода, чтобы попробовать его:

import * as lowDb from 'lowdb';
import * as FileAsync from 'lowdb/adapters/FileAsync';

/* first block just for generating random data... */
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
const charactersLength = characters.length;
const alphanum = (length: number) => {
    const result = new Buffer(length);
    for (let i = 0; i < length; i++ ) {
        result.write(characters.charAt(Math.floor(Math.random() * charactersLength)));
    }
    return result.toString('utf8');
};

class TestLowDb {
    private adapter = new FileAsync('test.json');
    private db;

    /* starting the db up, loading with Async FileAdapter */
    async startDb(): Promise<void> {
        return lowDb(this.adapter).then(db => {
            this.db = db;
            return this.db.defaults({executions: [], dbCreated: new Date()}).write().then(_ => {
                console.log('finished with intialization');
            })
        });
    }

    /* fill the database with data, fails quite quickly, finally produces a json like the following:
    * { "executions": [ { "id": "<ID>", "data": [ <data>, <data>, ... ] }, <nextItem>, ... ] } */
    async fill(): Promise<void> {
        for (let i = 0; i < 100; i++) {
            const id = alphanum(3);
            this.start(id); // add the root id for this "execution"
            for (let j = 0; j < 100; j++) {
                this.fireAndForget(id, alphanum(1000));
                // await this.wait(id, alphanum(1000));
            }
        }
    }

    /* for the first item in the list add the id with the empty array */
    start(id:string): void {
        this.db.get('executions')
            .push({id, data:[]})
            .write();
    }

    /* ignores the promise and continues to work */
    fireAndForget(id:string, data:string): void {
        this.db.get('executions')
            .find({id})
            .get('data')
            .push(data)
            .write();
    }

    /* returns the promise that the caller can handle it "properly" */
    async wait(id:string, data:string): Promise<void> {
        return this.db.get('executions')
            .find({id})
            .get('data')
            .push(data)
            .write();
    }
}

const instance = new TestLowDb();
instance.startDb().then(_ => {
    instance.fill()
});
enter code here
...