Node.jsで5MBを超える文字列を扱うことができない問題とその解決方法
概要
Node.jsを使っていると、5MBを超える文字列を扱う際に問題が発生することがあります。この問題は、大量のデータを一度にメモリに読み込もうとする際に起こります。特に、サーバーから大きなJSON文字列を受信する際に顕著です。本記事では、この問題の原因と解決方法について解説します。
現象
Node.jsで5MBを超える文字列を扱おうとすると、次のようなエラーが発生することがあります。
FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
このエラーは、Node.jsがメモリの限界を超えてデータを処理しようとする際に発生します。大きなデータを一度に読み込むと、メモリが不足し、結果としてアプリケーションがクラッシュしてしまいます。
原因
この問題の主な原因は、Node.jsが単一スレッドで動作し、メモリ管理がJavaScriptエンジン(V8)によって行われているためです。大量のデータを一度に処理しようとすると、メモリの使用量が急増し、ガベージコレクションが追いつかなくなります。その結果、メモリ不足が発生します。
解決方法
この問題を解決するための最良の方法は、バイナリデータとストリームを活用してデータを分割して処理することです。ストリームを使用することで、大量のデータを一度にメモリに読み込むのではなく、データを小さなチャンクに分割して処理できます。以下に、サーバーから5MBを超えるJSON文字列を受信する際に、ストリーム処理を行うサンプルコードを示します。
const axios = require('axios');
const { chain } = require('stream-chain');
const { parser } = require('stream-json');
const { pick } = require('stream-json/filters/Pick');
const { streamArray } = require('stream-json/streamers/StreamArray');
async function fetchAndProcessJson(url) {
try {
const response = await axios({
method: 'get',
url: url,
responseType: 'stream' // レスポンスをストリームとして取得
});
const pipeline = chain([
response.data, // axiosのレスポンスストリームを使用
parser(),
pick({ filter: 'contents_array' }), // 'contents_array'キーを抽出
streamArray() // 配列の各要素をストリーム処理
]);
pipeline.on('data', ({ key, value }) => {
// valueはcontents_arrayの各要素
processObject(value);
});
pipeline.on('end', () => {
console.log('Finished processing the JSON stream.');
});
pipeline.on('error', (err) => {
console.error('Error processing the JSON stream:', err);
});
} catch (error) {
console.error('Error fetching the JSON:', error);
}
}
function processObject(obj) {
// オブジェクトごとの処理を行う関数
console.log(obj);
}
// サンプルのURLを指定して関数を呼び出す
const url = '';
fetchAndProcessJson(url);
このコードでは、axios
を使用してサーバーからJSONデータをストリームとして取得し、stream-json
ライブラリを使用してデータを分割して処理しています。stream-json
は、大きなJSONデータを小さなチャンクに分割し、それぞれを順次処理することを可能にします。
まとめ
Node.jsで5MBを超える文字列を扱う際に発生するメモリ不足の問題は、ストリームを活用することで解決できます。大きなデータを一度に読み込むのではなく、ストリームを使用してデータを小さなチャンクに分割し、順次処理することでメモリの使用量を抑えることができます。この方法を活用することで、Node.jsアプリケーションのパフォーマンスと安定性を向上させることができます。
株式会社Grandreamでは、フルリモートであなたのスキルを活かし、活躍できるエンジニアを募集しております。
詳しくは採用ページをご確認いただき、お気軽にお問い合わせください。