увеличение использования памяти при каждом вызове api, nodejs

#node.js #express #canvas #memory-leaks #heap-memory

#node.js #экспресс #холст #утечки памяти #кучная память

Вопрос:

Спасибо, что прочитали это. у меня есть приложение node, которое преобразует текст в изображение, и каждый раз, когда я его использую, объем моей памяти увеличивается примерно с 14 до 40 МБ, и я не могу найти утечку памяти, я пробовал node-проверять и каждый раз, когда я достигаю функций, в которых нет утечек памяти.

это мое app.js

 const express = require('express'); const app = express(); var mysql = require('mysql');  //requiring modules const makeImage = require('./modules/makeImage.js'); const ThirdPageBodies = require('./modules/thirdPageBodies.js'); const ThirdPageTitles = require('./modules/thirdPageTitles.js'); const defImages = require('./modules/defImages.js');  require('dotenv').config({ path: '../.env' });//getting data from the laravel's .env file  const port = process.env.PIXATEX_PORT;  var con = mysql.createConnection({  host: process.env.DB_HOST,  user: process.env.DB_USERNAME,  password: process.env.DB_PASSWORD,  database: process.env.DB_DATABASE });  con.connect(function(err) {  if (err) throw err;  console.log("Connected!"); });  var laravel_path = '../storage/app/'; var Can = require("canvas"); //registering all the fonts  con.query('SELECT id, slug FROM fonts', async function (err, resu) {  if (err) throw err;   if(resu.length == 0){  console.log('wrong data');  }   resu.forEach(async font =gt; {  //======================================== getting font weights ==========================================gt;  con.query('select * from font_weights where font_id=${font['id']}', async function (err, result) {  if (err) throw err;    if(result.length == 0){  console.log('wrong data');  }    result.forEach(async function (weight){  Can.registerFont(laravel_path   weight['path'], { family: font['slug']   weight['name'] });  });  });  });  console.log('fonts were registered');  });  // Add headers before the routes are defined app.use(function (req, res, next) {   // Website you wish to allow to connect  res.setHeader('Access-Control-Allow-Origin', process.env.PIXATEX_FONTLAB_URL);   // Request methods you wish to allow  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');   // Request headers you wish to allow  res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');   // Set to true if you need the website to include cookies in the requests sent  // to the API (e.g. in case you use sessions)  res.setHeader('Access-Control-Allow-Credentials', true);   // Pass to next layer of middleware  next(); });  app.get('/makeImage', async (req, res) =gt; { //api to make images, returns dataUri  // delete require.cache[require.resolve('./modules/makeImage.js')];  makeImage.makeImage(req, res, con); });  app.get('/makeThirdPageBodies', (req, res) =gt; {  ThirdPageBodies.makeThirdPageBodies(req, res, con); });  app.get('/makeAllThirdPageBodies', (req, res) =gt; {  ThirdPageBodies.makeAllThirdPageBodies(req, res, con); });   app.get('/makeThirdPageTitles', (req, res) =gt; {  ThirdPageTitles.makeThirdPageTitles(req, res, con); });  app.get('/makeAllThirdPageTitles', (req, res) =gt; {  ThirdPageTitles.makeAllThirdPageTitles(req,res,con); });   app.get('/makeDefImages', (req, res) =gt; {// to make all the default images  defImages.makeDefImages(req, res, con); });  app.listen(port, () =gt; console.log('the app is listening'));  

и моя основная функция

  const textToImage = require('text-to-image'); const Can = require("canvas");  async function makeImage(req, res, con){   //validating incoming data  if (req['query']['text'] == undefined || req['query']['text'] == "") res.end('wrong data');  if (req['query']['font'] == undefined || req['query']['font'] == "") res.end('wrong data');  if (req['query']['weight'] == undefined || req['query']['weight'] == "") res.end('wrong data');   if (req['query']['text'].length gt;= 300) res.end('wrong data');   //a query to get the requested font's path from db.  con.query(`select font_weights.path, fonts.slug from fonts INNER JOIN font_weights on fonts.id = font_weights.font_id where font_weights.name = '${req['query']['weight']}' AND fonts.name = '${req['query']['font']}'`, async function (err, result) {  if (err) throw err;   if (result.length == 0) {//font wasn't found.  res.end('wrong data');  }   //Dems are for measuring the text.  var canvasDem = Can.createCanvas(1, 1);  var ctxDem = canvasDem.getContext('2d');   //generating images for page one.  if (req['query']['page'] == 'one') {   //making images for all sizes for more speed.  var sizes = [72, 60, 48, 36, 30, 28, 26, 24, 22, 20, 18, 17, 16, 15, 14, 13, 12];  var images = {};   sizes.forEach(async function (size) {  // await new Promise(r =gt; setTimeout(r, 10000));  size *= 2;  //measuring the text with the registered font  ctxDem.font = size   'px '   result[0]['slug']   req['query']['weight'];  var text = ctxDem.measureText(req['query']['text']);   var ratio = text.width / size;// this formula was learned throught trial and error  var widthControll = text.width / (ratio / 3);   while (text.width   widthControll gt; 14900) {  req['query']['text'] = req['query']['text'].substring(0, req['query']['text'].lastIndexOf(" "));  text = ctxDem.measureText(req['query']['text']);  }   //calculating lineHeight  lineHeight = text.emHeightAscent   text.emHeightDescent   (size / 3); //   (size / 3)??!!!!, these measurements were learned through trial and error   textToImage.generate(req['query']['text'], {  debug: false,  maxWidth: text.width   widthControll,  lineHeight: lineHeight,  fontSize: size,  fontFamily: result[0]['slug']   req['query']['weight'],  textAlign: "right",  bgColor: "transparent",  margin: 0  }).then(async function (dataUri) {  dataUri.toBuffer(async function (e, webpbuffer) {  images[(size / 2)] = 'data:image/webp;base64,'   webpbuffer.toString('base64');  let dr = true;  sizes.forEach(function (s) {  if (images[s] == undefined) dr = false;  });   if (dr == true) {   res.statusCode = 200;  res.setHeader('Content-Type', 'application/json');  res.end(JSON.stringify(images));  }  });  });   });  }  else if (req['query']['page'] == 'two') {// making images for the sacond page.   //validating the width coming from the request.  if (req['query']['width'] == undefined || req['query']['width'] == 0 || req['query']['width'] gt; 600) res.end('wrong data');   //generating for all sizes for more speed.  var sizes = [10, 12, 14, 16, 18];   var images = {};  sizes.forEach(function (size) {  size *= 2;  //measuring the text  ctxDem.font = size   'px '   result[0]['slug']   req['query']['weight'];  var text = ctxDem.measureText(req['query']['text']);  lineHeight = text.emHeightAscent   text.emHeightDescent   (size / 3); //   (size / 3)??!!!!, these measurements were learned through trial and error   textToImage.generate(req['query']['text'], {  debug: false,  maxWidth: parseInt(req['query']['width']) * 2, //width from the request  lineHeight: lineHeight,  fontSize: size,  fontFamily: result[0]['slug']   req['query']['weight'],  textAlign: "right",  bgColor: "transparent",  margin: 0  }).then(function (dataUri) {  dataUri.toBuffer(function (e, webpbuffer) {  images[(size / 2)] = 'data:image/webp;base64,'   webpbuffer.toString('base64');  let dr = true;  sizes.forEach(function (s) {  if (images[s] == undefined) dr = false;  });   if (dr == true) {   res.statusCode = 200;  res.setHeader('Content-Type', 'application/json');  res.end(JSON.stringify(images));  }  });  });   });  }   }); }  module.exports = {makeImage};   

возможно, это будет бесполезно, но это моя проверка

Комментарии:

1. мой размер кучи составляет около 13 МБ, но RSS становится все больше и больше, сервер вышел из строя, когда я попробовал некоторые из своих функций, OOM не работает.