#node.js
#node.js
Вопрос:
У меня есть приложение NodeJS на Elastic Beanstalk.
Я загружаю большое количество больших архивов, открываю и обрабатываю их, а затем удаляю zip-файлы с помощью fs.unlinkSync
При тестировании я вижу, что файлы удаляются, но, по-видимому, unlink фактически не освобождает пространство, пока процесс его использует?
Как я могу поручить fs освободить выделенную память?
Я записываю файл через
let writeStream = fs.createWriteStream(file.name);
writeStream.on('finish', () => {
// a bunch of logic that eventually returns a promise
и внутри его разрешения / отклонения
fs.unlinkSync(file.name)
Я прошел, и это единственный раз, когда я касаюсь файла, все остальное закрыто. Есть ли какое-то другое событие, которого мне нужно дождаться для закрытия потока записи?
— для полного объяснения рабочего процесса
for (let i = 0; i < records.length; i ) {
await processZip(records[i]);
fs.unlinkSync(records[i].name);
}
внутри метода processZip
return new Promise(async (resolve, reject) => {
var readStream = this.s3Access.getObjectStream(guid);
let writeStream = fs.createWriteStream(file.name);
readStream.pipe(writeStream);
writeStream.on('finish', () => {
resolve();
}
}
Комментарии:
1. Вы должны позволить gc выполнять свою работу. Используйте
nextTick
и убедитесь, что вы освободили переменные, содержащие память
Ответ №1:
Согласно документам NodeJS unlinkSync()
, вызывается вызов C / C API unlink
.
Вот что говорится в документах
unlink() удаляет имя из файловой системы. Если это имя было последней ссылкой на файл и ни один процесс не открыл файл, файл удаляется, а занимаемое им пространство становится доступным для повторного использования.
Если имя было последней ссылкой на файл, но какие-либо процессы все еще открывают файл, файл будет существовать до тех пор, пока не будет закрыт последний файловый дескриптор, ссылающийся на него.
Если имя ссылается на символическую ссылку, ссылка удаляется.
Если имя ссылается на сокет, FIFO или устройство, его имя удаляется, но процессы, у которых объект открыт, могут продолжать его использовать.
В принципе, все ссылки должны быть закрыты для удаления файла.
Попробуйте подумать о других процессах, которые могут использовать файлы, которые вы пытаетесь удалить (файлы, открытые с fs.open/openSync()
помощью которых не были закрыты и т.д.)
ОБНОВЛЕНО
Похоже, что файл удаляется после processZip
успешного выполнения обещания, возвращенного.
Было бы полезно также удалить файл, если обещание было отклонено (т.Е. Ошибка, вызванная асинхронной функцией).
for (let i = 0; i < records.length; i ) {
try {
await processZip(records[i]);
} finally {
// delete file after success or error
fs.unlinkSync(records[i].name);
}
}
Кроме 'error'
того, обработчики событий могут быть добавлены в оба потока processZip
.
Я нашел эту заметку в stream.pipe()
документах, возможно, это связано с проблемой:
Одним из важных предостережений является то, что если
Readable
поток выдает ошибку во время обработки,Writable
назначение не закрывается автоматически. В случае возникновения ошибки необходимо будет вручную закрыть каждый поток, чтобы предотвратить утечки памяти.
return new Promise(async (resolve, reject) => {
var readStream = this.s3Access.getObjectStream(guid);
let writeStream = fs.createWriteStream(file.name);
readStream.pipe(writeStream);
writeStream.on('finish', () => {
resolve();
}
readStream.on('error', err => {
readStream.end();
writeStream.end();
reject(err);
}
writeStream.on('error', err => {
readStream.end();
writeStream.end();
reject(err);
}
}
Комментарии:
1. Привет, Виталий, спасибо за предложение, я проверил и убедился, что никаких других ссылок или ссылок на файл нет, и обновил свой вопрос, чтобы показать
2. Привет, Джошуа, я нашел в документах дополнительную информацию об обработке ошибок и добавил в свой ответ предложение по обработке ошибок для вашего кода.