Доброго времени суток, друзья. Поговорим сегодня о работе с файлами в Node.js. Для работы с файлами используется модуль fs (сокращение от File System).
В этой статье мы рассмотрим следующие темы:
— Работа с файловыми дескрипторами;
— Работа с директориями;
— Создание новой папки;
— Чтение содержимого папки;
— Получение системной информации о файле;
— Модуль path и путь к файлу;
— Получение имени, пути и расширения файла;
— Работа с путями файла;
— Переименование файла или директории;
Для начала работы нам потребуется установленная Node.js. Подробную инструкцию по ее установке вы можете получить (тут).
Прежде чем начать работу с модулем, его следует импортировать в рабочем файле.
const fs = require(‘fs’);
Пробежимся по основным методам этого модуля и посмотрим на примерах как с ними можно работать.
Работа с файловыми дескрипторами
Прежде чем двигаться дальше, давайте посмотрим на термины, о которых описано в статье ниже.
Что такое Дескриптор в бизнесе
Файловый дескриптор — это неотрицательное целое число. Когда создается новый поток ввода-вывода, ядро возвращает процессу, создавшему поток ввода-вывода, его файловый дескриптор (Wikipedia).
Если излагать простыми словами, то при открытии файла мы получаем его дескриптор — это уникальный индикатор, благодаря которому мы можем отслеживать каждый файл отдельно и работать с ним. Для получения дескриптора файла в Node.js используются два метода: (1) асинхронный метод fs.open() и (2) синхронный fs.openSync(). К слову все методы в Node.js имеют синхронные и асинхронные реализации.
Синхронные методы отмечены в название метода с окончанием Sync. В чем же разница между синхронным и асинхронным методами? Главное отличие — это порядок их выполнения. Синхронный метод будет выполнен путем блокирования основного потока, в тоже время, если для того же действия использовать ассинхронный метод, то операции могут быть выполнены в произвольном порядке по истечению их выполнения (т.к. основной поток не будет блокироваться).
Перейдем к примерам.
const fs = require(‘fs’) // асинхронный fs.open(‘template.txt’, ‘r’, (err, fd) => < if (err) throw err; //fd — это дескриптор файла console.log(fd) >) // синхронный try < const fd = fs.openSync(‘template.txt’, ‘r’) console.log(fd) >catch (err)
В этих примерах при выполнении кода, мы получим уникальный дескриптор файла. Пройдемся по параметрам методов. Первый — это путь к файлу, который читаем. Второй параметр предназначен для передачи флагов доступа к файлам.
В данном примере мы указали параметр ‘r’, что означает этот файл открыт для чтения.
Ниже я приведу перечень флагов доступа к файлам
r+ — чтение и запись;
w+ — чтение и запись, запись с начала файла. Файл создается если его нет;
a — запись, запись с конца файла. Файл создается если его нет;
a + — чтение и запись, запись с конца файла. Файл создается если его нет;
Дескриптор. Дескриптор сайта
Третий параметр отличается в зависимости от типа метода. В асинхронном варианте это колбэк функция, первый аргумент которой возвращает ошибку (в случае ее возникновения), а второй — сам дескриптор. Если метод синхронный, то вызов происходит в блоке try/catch для отслеживания ошибок и получения ответа путем присвоения вызова переменной.
Следует помнить, что дескрипторы файлов необходимо закрывать для предотвращения переполнения памяти, а также проблем с производительностью. Выполним данную задачу с помощью метода close() и его синхронного аналога closeSync().
Работа с директориями
Для проверки существующей директории (файла) и доступов к нему в модуле fs применяется метод access
const fs = require(‘fs’) const file = ‘package.json’; // проверка существования файла fs.access(file, fs.constants.F_OK, (err) => < console.log(`$$`); >); // проверка на возможность прочитать файл fs.access(file, fs.constants.R_OK, (err) => < console.log(`$$`); >); // проверка на возможность перезаписать файл fs.access(file, fs.constants.W_OK, (err) => < console.log(`$$`); >);
Вторым параметром устанавливается константа режима проверки:
F_OK — существование файла без проверки прав доступа;
R_OK — может ли файл быть прочитан текущим процессом;
W_OK — может ли файл быть записан текущим процессом;
X_OK — может ли файл быть выполнен текущим процессом (в Windows не работает).
Создание новой папки
Для создания каталогов присутствует асинхронный метод mkdir и синхронный mkdirSync.
fs.mkdir(__dirname + dir, < recursive: true >, (err) => < if (err) < console.error(err) return >>) if (!fs.existsSync(dir)) < try < fs.mkdirSync(__dirname + dir, < recursive: true >) > catch (error) < console.error(error) >> else
Для создания в текущей директории нового каталога, перед путем следует указать переменную __dirname как вариант реализации абсолютного пути, либо воспользоваться метом resolve модуля path.
Чтение содержимого папки
Для получения содержимого директории используются два метода readdir и readdirSync. Первым параметром для методов передается путь директории, содержимое которой нужно получить.
const fs = require(‘fs’) const dir = __dirname + ‘/’ fs.readdir(dir, (err, files) => < if (err) < console.error(err) return >console.log(files) >) try < const files = fs.readdirSync(dir) console.log(files) >catch (error)
Удаление папки
Удаление директории производится с помощью методов rmdir и rmdirSync. Первым параметром методов является путь удаляемой директории.
const fs = require(‘fs’) fs.rmdir(__dirname +’/testDel’, () => < console.log(‘Файл успешно удален’) >) try < fs.rmdirSync(__dirname + ‘/testDel’) console.log(‘Файл успешно удален’) >catch (error)
Получение системной информации о файле
Каждый файл, который мы загружаем, помимо данных хранит в себе системную информацию. Для получения этой информации можно воспользоваться методом stat() или выбрать синхронный вариант statSync()
// асинхронный fs.stat(‘template.txt’, (err, stats) => < if (err) < console.error(err) return >console.log(stats) >) // синхронный try < const stats = fs.statSync(‘template.txt’) console.log(stats) >catch (err)
Вся информация хранится в получаемом объекте stats. Данный объект хранит в себе методы для получения дополнительной полезной информации.
Перечислю некоторые из этих свойств:
stats.isDirectory() метод позволяет узнать, является ли файл директорией;
stats.isFile() метод возвращает true, если это файл;
stats.isSocket() метод возвращает true, если это сокет;
stats.isSymbolicLink() метод возвращает true, если файл является символьной ссылкой;
stats.size свойство, которое возвращает размер файла;
stats.birthtime возвращает время и дату, когда данный файл был создан.
fs.stat(‘template.txt’, (err, stats) => < if (err) < console.error(err) return >console.log(stats.isDirectory()) console.log(stats.isFile()) console.log(stats.isSocket()) console.log(stats.isSymbolicLink()) console.log(stats.size) console.log(stats.mode) console.log(stats.birthtime) >)
Модуль path и путь к файлу Node.js
Основной проблемой при работе с файлами и папками в операционных системах является разный синтаксис написания путей их расположения. Для решения этой проблемы в Node.js есть модуль path c набором полезных методов.
Для началы работы с модулем его нужно импортировать.
const path = require(‘path’);
Получение имени, пути и расширения файла
Предположим, что в папке /temp лежит файл template.txt. Воспользуемся методами модуля path для получения имени файла, пути к нему, а так же его расширения.
const file = ‘/temp/tempalate.txt’ path.basename(file) // tempalate.txt
Метод basename возвращает наименование файла. Первым параметром передается путь к файлу, вторым параметром (опционально) передается расширение файла, если необходимо получить наименование файла без расширения.
path.basename(file, ‘.txt’) // tempalate
path.basename(file, ‘.txt’) // tempalate
Метод dirname возвращает весь путь директории, где лежит файл и имеет один параметр, в который передается путь к файлу.
path.dirname(file) // /temp
Метод extname возвращает расширение переданного файла.
path.extname(file) // .txt
Работа с путями файла
В модуле path есть ряд методов для удобного формирования путей к нужному файлу или директории. Мы не будем рассматривать все методы, а только наиболее часто используемые. Рассмотрим их ниже.
Метод join принимает список параметров, объединяет их в одну строку, используя разделитель, подходящий к конкретной операционной системе, в которой будет исполнятся код.
const folderName = ‘temp’ path.join(‘/’, folderName, ‘template.txt’) // /temp/template.txt
Метод resolve используется для нахождения абсолютных путей к файлу.
path.resolve(‘template.txt’) // Users/Desktop/dev/node-fs/template.txt path.resolve(folderName, ‘template.txt’) // /Users/Desktop/dev/node-fs/temp/template.txt path.resolve(‘/temp’, ‘template.txt’) // /temp/template.txt
Метод normalize позволяет найти путь к файлу, используя синтаксис переходов (.. и .) по папкам.
path.normalize(‘/users/../temp/template.txt’) // temp/template.txt
Переименование файла или директории
Методы rename() и renameSync() первым параметром принимают путь к файлу, который нужно переименовать. Второй параметр отвечает за новое наименование файла.
const fs = require(‘fs’) // переименовываем файла fs.rename(‘oldFile.txt’, ‘newFile.txt’, (err) => < if (err) throw err; console.log(‘Файл переименован’); >); // переименовываем директорию try < fs.renameSync(‘./oldDir’, ‘./newDir’) console.log(‘Папка переименован’); >catch (error)
Чтение файла
const fs = require(‘fs’) // асинхронное fs.readFile(‘template.txt’, ‘utf-8’, (err, data) => < if (err) < console.error(err) return >console.log(data) >) // синхронное try < const data = fs.readFileSync(‘template.txt’, ‘utf-8’) console.log(data) >catch (err)
Если вторым параметром не указана кодировка, то возвращается Buffer. Эти методы полностью загружают файлы в память компьютера, что может сильно отразиться на производительности. Если размер файла большой, то стоит воспользоваться потоками fs.createReadStream()
Запись файла
Чтобы перезаписать контент файлов, используются методы writeFile и writeFileSync. Важный момент! Если файла, контент которого нужно перезаписать, не существует, то он будет создан автоматически.
const fs = require(‘fs’) const content = ‘Новый текст’ fs.writeFile(‘newText.txt’, content, (err) => < if (err) < console.error(err) return >console.log(‘файл успешно перезаписан’) >) try < fs.writeFileSync(‘newTextTwo.txt’, content) console.log(‘файл успешно перезаписан’) >catch (err)
Копирование файла
Методы copyFile() и copyFileSync() первым параметром принимают путь файла для копирования. Второй параметр принимает название пути и нового файла. Третьим параметром является колбэк функция, которая возвращает ошибку.
const fs = require(‘fs’) fs.copyFile(‘oldFile.txt’, ‘oldFileTwo.txt’, (err) => < if (err) < console.error(err) return >console.log(‘Файл успешно копирован’) >); try < fs.copyFileSync(‘oldFile.txt’, ‘oldFileTwo.txt’) console.log(‘Файл успешно копирован’) >catch (error)
Удаление файла
Последнее, что мы рассмотрим в этой статье будут методы unlink() и unlinkSync(). Первым параметром методы принимают путь к удаляемому файлу. Второй параметр в методе unlink возвращает колбэк функцию с ошибкой.
const fs = require(‘fs’) fs.unlink(‘file.txt’, (err) => < if (err) throw err; console.log(‘Файл успешно удален’); >); try < fs.unlinkSync(‘file.txt’) console.log(‘Файл успешно удален’); >catch (error)
Заключение
В данной статье мы разобрали работу Node.js с файлами, на примерах посмотрели основные полезные методы модулей fs и path. Исходный код вы сможете найти тут. Надеюсь данная статья была вам полезна. Учитесь, думайте, пишите код.
Удачного кодинга, друзья!
Подписывайтесь на наш канал в Telegram и на YouTube для получения самой последней и актуальной информации.
Источник: webtricks-master.ru
Дескриптор
Дескриптор — очень важная штука. Люди, когда заходят на сайт, должны понимать, куда попали. Дескриптор может быть общим для всего сайта, и это не будет ошибкой. Не переживайте, что он получится слишком большим. Можно дескриптор сделать индивидуальным — для отдельных разделов, страниц и т. д.
Итак, что же такое дескриптор? Это описание вашей компании и тех товаров/услуг, которые вы предлагаете клиентам.
Пример первый
Возьмём любой сайт. Пускай это будет сайт, предлагающий потребителю гарантированно качественную сантехнику, аксессуары для общественных и личных санузлов.
Что можно в его дескриптор вынести? Товары, которые он реализует, способ реализации (опт или розница), географию (Москва, Россия или весь мир).
Конечно, всю эту информацию при желании на сайте можно найти. Но для этого пользователю нужно посмотреть налево/направо, обладать определённым умением пользоваться навигацией, то есть иметь хоть какую-то пользовательскую квалификацию. Иначе ничего этого какая-нибудь бабушка или женщина средних лет попросту не увидит.
Вариант дескриптора в этом случае может быть таким →
«Интернет-магазин аксессуаров для общественных и личных санузлов с доставкой по Москве и Московской области».
Ещё один пример
Сайт реализует насосы и скважины: об этом можно прочитать в тайтле. Однако в тайтл обычно кто смотрит? Сеошник со стажем — по профессиональной привычке. На самом деле большинство пользователей на тайтл даже не взглянет, тем более что в современных браузерах он уже не так заметен.
Навигация? Выход, конечно. Но, если в ней очень много пунктов, нужно тратить усилия, чтобы разобраться. Кроме того, сразу из навигации тоже не поймёшь, с доставкой предлагается товар или без доставки, оптом или в розницу.
Какой выход?
Обобщить все предлагаемые товары в одну категорию, указать, в каком регионе и как реализуется товар, предусмотрена ли доставка продукции и т. д. И вот когда я всё это увижу на сайте сразу под логотипом компании, то сразу определю, туда я попал или нет.
А если мне придётся поковыряться в навигации, чтобы отыскать то, чем компания торгует, я скорее всего буду искать (и найду!) 3-4 сайта конкурента, на которых вся интересующая меня информация будет вынесена в дескриптор.
Об услугах
Сайт посвящён налоговым новостям и услугам по оптимизации налогов. Но такой формулировки может быть недостаточно, потому что возникают вопросы: где и для кого проводится эта самая оптимизация? Поэтому нужно обязательно дополнить эту информацию. И не забываем подчёркивать ссылки. Потому что они должны быть подчёркнуты: есть такой прописанный во всех стандартах закон.
Что нужно помнить о дескрипторе?
Дескриптор — обобщающее описание товаров и услуг, которые предлагает компания.
— быть не очень коротким, но в то же время – лаконичным и чётким;
— открываться пользователю на любой странице сайта;
— давать ответы на вопросы, чем вы занимаетесь, для кого и где;
— обязательно включать какое-то бронебойное преимущество перед конкурентами.
Так выглядит стандартная форма. Кстати, подумайте на досуге сами над тем, что можно включить в дескриптор. Проявите креативность, фантазию! Пусть это станет вашим своеобразным домашним заданием.
Попробуйте составить разные варианты дескриптора и проведите блиц-опрос среди клиентов, знакомых, какой из них более понятный, привлекательный и какой максимально полно отражает суть вашей деятельности.
Источник: eggo.ru
Преодолевая границы Windows: дескрипторы
Это уже пятая статья из моей серии публикаций «Преодолевая границы Windows», в которых я рассказываю о максимальном значении и объеме ресурсов, которыми управляет Windows, таких как физическая память, виртуальная память, процессы и потоки:
На этот раз я собираюсь разобраться в реализации дескрипторов, чтобы найти и объяснить существующие для них ограничения. Дескрипторы — это структуры данных, которые представляют собой открытые экземпляры базовых объектов операционной системы, с которыми взаимодействуют приложения; например, файлы, ключи системного реестра, примитивы синхронизации и общая память. Существует два ограничения, связанные с количеством дескрипторов, которое может создать процесс: максимальное число дескрипторов, которое система может установить для процесса, и объем памяти, доступный для хранения дескрипторов и объектов, которые приложение связывает с их дескрипторами.
В большинстве случаев эти ограничения для дескрипторов находятся далеко от тех значений, которые обычно используются приложениями или системой. Однако, приложения, при разработке которых не учитывались эти ограничения, могут достигнуть их неожиданными для разработчиков путями. Чаще всего подобные проблемы возникают из-за того, что срок жизни этого вида ресурсов должен управляться приложениями, и, как в случае с виртуальной памятью, задача управления сроком жизни ресурсов является своего рода вызовом даже для самых лучших разработчиков. Приложение, которое не в состоянии освобождать неиспользуемые ресурсы, вызывает их утечку, что, в конечном счете, может привести к тому, что предел использования ресурса будет достигнут, приводя к странному и трудно диагностируемому поведению как данного, так и других приложений, или же всей системы в целом.
Как обычно, я рекомендую вам прочитать мои предыдущие публикации, поскольку в них объясняются некоторые из понятий, используемых в данной статье (например, выгружаемый пул).
Дескрипторы и объекты
Ядро Windows, работающее в привилегированном режиме, реализованное в образе %SystemRoot%System32Ntoskrnl.exe, состоит из различных подсистем, таких как диспетчер памяти, диспетчер процессов, диспетчер ввода/вывода, диспетчер конфигураций (системный реестр), которые является частями исполнительной системы. Каждая из этих подсистем вместе с диспетчером объектов определяет один или более типов для представления ресурсов, которые они выделяют приложениям. Например, диспетчер конфигураций определяет объект «ключ» (Key) для представления открытого ключа системного реестра; диспетчер памяти объект «Секция» (Section) для общей памяти; исполнительная система определяет объекты «семафор» (Semaphore), «мутант» (Mutant, внутреннее название для мьютекса) и «синхронизация событий» (Event synchronization) (эти объекты представляют собой оболочку для структур данных, определенных подсистемой Ядро операционной системы); диспетчер ввода/вывода определяет объект «файл» (File) для представления открытых экземпляров ресурсов драйверов устройств, которые включают в себя файлы файловой системы; и, наконец, диспетчер процессов создает объекты «поток» (Thread) и «процесс» (Process), о которых я рассказывал в своей последней публикации из данной серии. Каждый релиз Windows вводит новые типы объектов, в том числе и Windows 7, которые принес с собой в общей сложности 42 новых типа. Определенный в вашей системы объекты вы можете увидеть при помощи утилиты Winobj от Sysinternals, запущенной с правами администратора, открыв директорию ObjectTypes пространства имен Object Manager:
Когда приложение желает получить управление над одним из этих ресурсов, оно сначала должно вызвать соответствующий API, чтобы создать или открыть ресурс. Например, функция CreateFile открывает или создает файл, функция RegOpenKeyEx открывает ключ реестра, а функция CreateSemaporeEx открывает или создает семафор. Если такая функция успешно выполняется, Windows размещает дескриптор в таблице дескрипторов процесса приложения и возвращает значение этого дескриптора, которое приложение обрабатывает неявно, однако фактически речь идет об индексе возвращенного дескриптора в таблице дескрипторов.
Имея в своем распоряжении дескриптор, приложение делает запросы и управляет объектом, передавая значение дескриптора в такие функции API, как ReadFile , SetEvent , SetThreadPriority и MapViewOfFile . Система может организовать поиск объекта, к которому обращается дескриптор путем индексирования таблицы дескрипторов, чтобы определить местонахождения соответствующей дескриптору записи, которая содержит указатель на объект. Запись дескриптора также хранит информацию об операциях, которые стали доступны процессу, когда он открыл объект, что позволяет системе быть уверенной в том, что процесс не сможет выполнять над объектом операции, на которые у этого процесса нет разрешения. Например, если процесс успешно открыл файл для чтения, то запись дескриптора выглядела примерно так:
Если бы этот процесс попытался бы что-то записать в файл, то функция завершила выполнение с ошибкой, поскольку подобный вид доступа к файлу не был предоставлен, а факт кэширования доступа на чтение означает, что система не должна снова повторять более затратную в плане ресурсов проверку прав доступа.
Максимальное число дескрипторов
Чтобы исследовать первое ограничение вы можете воспользоваться инструментальным средством Testlimit, которое я уже использовал в рамках данной серии статей для того, чтобы опытным путем изучить ограничения на ресурсы системы. Его можно скачать на странице Windows Internals здесь . Для определения количества дескрипторов, которое может создать процесс, Testlimit используется с параметром -h, который указывает ему создать столько дескрипторов, сколько возможно. Это достигается путем создания объекта event с помощью функции CreateEvent и последующего неоднократного дублирования возвращаемого системой дескриптора с помощью функции DuplicateHandle . Используя дублирование, Testlimit избегает необходимости создания новых объектов и все ресурсы, потребляемые этим инструментов, расходуются для записей таблицы дескрипторов. Вот результат работы Testlimit с ключом -h в 64-битной системе:
Этот результат, однако, не отображает общее количество дескрипторов, которые может создать процесс, поскольку системные библиотеки DLL открывают различные объекты во время инициализации процесса. Общее число дескрипторов процесса вы можете увидеть, добавив соответствующую колонку в диспетчере задач или Process Explorer. Общее цифра для Testlimit в данном случае равна 16’771’680:
Когда вы запускаете Testlimit на 32-битной системе, число дескрипторов будет немного отличаться:
Общее число дескрипторов также другое, 16’744’448:
Чем обуславливаются эти различия? Ответ состоит в том, что исполнительная система, ответственная за управление таблицей дескрипторов, устанавливает ограничение на количество дескрипторов для каждого процесса, а также на размер записи в таблице дескрипторов.
Здесь мы имеем дело с одним из тех редких случаев, когда Windows устанавливает жесткое ограничение на использование ресурса, так что в данном случае исполнительная система определяет число 16’777’216 (16*1024*1024) как максимальное количество дескрипторов, которое может быть выделено процессу. Любой процесс, которые имеет более десяти тысяч дескрипторов одновременно в какой-либо момент времени, весьма вероятно имеет либо серьезные недочеты, допущенные при его проектировании, или утечку дескрипторов. Так что предел в 16 миллионов дескрипторов практически недостижим и призван помочь предотвратить утечку памяти, вызванную вмешательством в работу процесса со стороны остальной системы. Чтобы понять причину того, почему число, отображаемое в диспетчере задач, отличается от жестко установленного максимума, требуется рассмотреть то, каким образом исполнительная система организовывает таблицу дескрипторов.
Запись таблицы дескрипторов должна иметь достаточный размер для того, чтобы хранить маску прав доступа и указатель на объект. Маска доступа является 32-битной, но размер указателя, очевидно, зависит от того, является система 32-битной или 64-битной. Следовательно, запись дескриптора занимает 8 байт на 32-битной Windows и 12-байт на 64-битной Windows. 64-битная Windows дополняет структуры данных записи дескриптора до 64-битных границ, так что 64-битная запись дескриптора фактически занимает 16 байт. Вот определение записи дескрипторов на 64-битной Windows, отображенное в отладчике ядра с помощью команды dt (dump type):
Здесь мы видим, что данная структура содержит в себе и другую информацию, помимо указателя на объект и маски доступа, выделенных на скриншоте.
Исполнительная система размещает таблицы дескрипторов в блоки, имеющие размер страницы, которые она делит на записи таблицы дескрипторов. Это означает, что страница, которая занимает 4096 байт и на системах x86, и на системах x64, может сохранить 512 записей в 32-битной Windows и 256 записей в 64-битной Windows. Исполнительная система определяет максимальное число страниц, которые она может выделить под записи дескрипторов, путем деления жестко установленного максимума (16’777’216) на число записей дескрипторов на странице; для 32-битной Windows это число равно 32’768, а для 64-битной Windows — 65’536. Поскольку исполнительная система использует первую запись на каждой странице для своей собственной идентификационной информации, действительное количество дескрипторов, доступных для процесса, следует получать, вычитая из 16,777,216 полученные выше числа, что объясняет результаты, полученные при запуске Testlimit: 16’777’216 — 65’536 = 16’711’680 и 16’777’216 — 32’768 = 16’744’488.
Дескрипторы и выгружаемый пул
Вторым ограничением, касающимся дескрипторов, является объем памяти, требуемой для хранения таблицы дескрипторов, который исполнительная система выделяет из выгружаемого пула. Исполнительная система для отслеживания выделяемых ею под таблицы дескрипторов страниц использует трехуровневую схему, подобную той, которую используют модули управления памятью (MMU) процессора для руководства трансляциями виртуальных адресов в физические. Мы уже рассматривали с вами организацию нижнего и среднего уровней, которые фактически хранят в себе записи таблицы дескрипторов. Верхний уровень служит в качестве указателей на таблицы среднего уровня и включает в себя 1024 записи на страницу в 32-битной Windows. Отсюда следует, что общее количество страниц, требуемых для хранения максимального числа дескрипторов для 32-битной Windows можно вычислить как 16’777’216/512*4096, что равно 128 Мб. Это совпадает с показателями использования Testlimit выгружаемого пула, которые показывает диспетчер задач:
В 64-битной версии Windows на верхнем уровне содержится 256 указателей на страницу. Это означает в общем для размещения полной таблицы дескрипторов используется 256 Мб выгружаемого пула (16’777’216/256*4096). Правильность данных вычислений подтверждается показателями использования Testlimit выгружаемого пула на 64-битной Windows:
Объема выгружаемого пула более чем достаточно, чтобы сохранить эти структуры данных, однако, как я уже говорил ранее, процесс, который создает слишком много дескрипторов, почти наверняка исчерпает какой-то другой ресурс, и, если он достигнет ограничения на количество дескрипторов для одного процесса, то ему не удастся открыть никакие другие объекты.
Утечки дескрипторов
Для процесса, допускающего утечку дескрипторов характерно то, что число потерянных дескрипторов постоянно возрастает. Причина этого кроется в том, что утечка дескрипторов очень коварна — в отличие от случая с Testlimit, который создавал дескрипторы для одного и того же объекта, процесс, имеющий утечку дескрипторов, вероятнее всего теряет вместе с ними и объекты. Например, если процесс создает события, но не может закрыть их, он создает утечку как записей дескрипторов, так и объектов событий. Объекты «event» располагаются в невыгружаемом пуле, так что данная утечка затронет в дополнение к выгружаемому пулу и невыгружаемый пул.
Вы можете визуально определить объекты, доступ к которым потерял процесс, используя представление дескрипторов в Process Explorer, поскольку там новые дескрипторы выделены зеленым, а закрытые — красным; если вы увидите много зеленых записей при малом количестве красных, значит вы, скорее всего, столкнулись с утечкой. Чтобы увидеть подобное выделение дескрипторов Process Explorer в действии, вы можете открыть процесс командной строки и, выбрав этот процесс в Process Explorer, перейти к просмотру дескрипторов, после чего следует сменить текущую директорию в командной строке. Дескриптор старой рабочей директории подсветится красным, а новой — зеленым:
По умолчанию Process Explorer показывает только дескрипторы, которые указывают на объекты, имеющие имена, что означает, что вы не увидите всех дескрипторов процесса, если не включите опцию «Show Unnamed Handles and Mappings» в меню View. Вот некоторые безымянные дескрипторы из таблицы дескрипторов командной строки:
Как и в случае с большинством других ошибок, только разработчик кода, из-за которого происходит утечка, может исправить это. Если вы обнаружили утечку у процесса, который состоит из нескольких компонентов или расширений, например, Explorer, Service Host или Internet Explorer, то главный вопрос состоит в том, какая из этих частей ответственна за утечку. Определение такого компонента позволило бы вам избежать появления проблемы, отключив или удалив проблемное расширение, проверить его на наличие обновлений, исправляющих эту ошибку или сообщить о ней разработчику.
К счастью, Windows включает в себя средство отслеживания дескрипторов, которое вы можете использовать для установления факта утечки и определения ответственного за эту утечку программного обеспечения. Оно работает с каждым процессом в отдельности и активируется исполнительной системой для записи активности стека каждый раз, когда какой-либо дескриптор создается или закрывается. Вы можете воспользоваться этим инструментом или при помощи утилиты Application Verifier , которую можно бесплатно скачать с сайта Microsoft, или воспользовавшись отладчиком Windows (Windbg) . Если вы хотите, чтобы система проследила за активностью дескрипторов процесса, начиная с его запуска, то вам нужно использовать Application Verifier. В остальных случаях вам нужно использовать отладчик и команду !htrace , чтобы увидеть информацию об активности процесса.
Чтобы продемонстрировать отслеживание активности в действии, я запустил Windbg и подключился к командной строке, которую я запустил ранее. Чтобы включить отслеживание дескрипторов, я ввел команду !htrace с ключом -enable:
Я позволил процессу продолжать работу и снова сменил директорию. После этого я переключился обратно на Windbg, остановил выполнение процесса и запустил команду htrace без параметров, которая выдает список всех открытых и закрытых операций, которые выполнил процесс, начиная с предыдущего запуска команды !htrace с параметром snapshot или с того момента, когда была включена запись активности дескрипторов. Вот результаты работы этой команды для той же сессии отладчика:
Здесь перечислены события, начиная с самой последней операции, так что, если читать снизу, мы увидим, что командная строка открыла дескриптор 0xb8, затем закрыла его, потом открыла дескриптор 0x22c и в конце закрыла дескриптор 0xec. Process Explorer отметил бы дескриптор 0x22c зеленым и 0xec красным, если бы он был обновлен после смены директории, но, по всей вероятности, не увидел бы 0xb8, если бы обновление не произошло между открытием и закрытием этого дескриптора. Стек для открытия 0x22c показывает, что данная операция стала результатом выполнения командной строкой (cmd.exe) своей функции ChangeDirectory. Если добавить в Process Explorer колонку Handle, она подтвердит, что новый дескриптор — 0x22c:
Если вы ищите только утечки, то вам нужно использовать !htrace с параметром -diff, которая показывает только новые дескрипторы, начиная с последней засечки или с начала запуска отслеживания активности. Как и ожидалось, в результате выполнения этой команды мы видим только дескриптор 0x22c:
Прекрасным источником советов о том, как можно устранить утечки дескрипторов является интервью инженера по технической поддержке Microsoft Джеффа Дэйли (Jeff Dailey) для Channel 9.
В следующий раз я рассмотрю ограничения, установленные для таких основанных на дескрипторах ресурсов, как объекты GDI и USER. Дескрипторы этих ресурсов управляются подсистемой Windows, отличной от исполнительной системы, а потому используют другие ресурсы и имеют другие ограничения.
Источник: www.thevista.ru