#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 не работает.