部署Node.js+Express集成Google APIs至EC2时遇JavaScript堆内存溢出
Node.js + Express 集成Google APIs部署EC2时内存溢出问题
我正在构建一个基于Node.js和Express集成Google APIs的服务,本地环境运行一切正常,但部署到EC2实例时,出现JavaScript heap out of memory错误,导致应用崩溃。移除实例化OAuth2Client的代码后,应用即可正常运行。
问题详情
index.ts
import express from 'express'; import dotenv from 'dotenv'; import { google } from 'googleapis'; // ... 更多模板代码 const googleApiRoutes = require('./routes/googleApiRoutes'); app.use('/api/google-api', googleApiRoutes); // 导致应用崩溃的实例化代码 export const OAuth2Client = new google.auth.OAuth2( process.env.GOOGLE_APIS_CLIENT_ID, process.env.GOOGLE_APIS_CLIENT_SECRET, process.env.GOOGLE_API_REDIRECT_URL ); app.listen(process.env.PORT || 5007, () => { console.log(`[server]: Server is running at http://localhost:5007`); });
package.json
{ "name": "loopfive-services", "version": "1.0.0", "description": "A general service api useful for various projects", "main": "index.ts", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "prettier": "prettier --write .", "start": "nodemon index.ts" }, "author": "Ilyes Hadji", "license": "ISC", "dependencies": { "@types/express": "^4.17.21", "@types/node": "^22.0.0", "body-parser": "^1.20.2", "config": "^3.3.6", "cookie-parser": "^1.4.6", "cors": "^2.8.5", "dotenv": "^16.4.5", "express": "^4.18.3", "express-formidable": "^1.2.0", "express-session": "^1.17.2", "express-validator": "^7.0.1", "form-data": "^4.0.0", "formidable-serverless": "^1.1.1", "google-auth-library": "^9.14.0", "googleapis": "^142.0.0", "helmet": "^4.4.1", "mailgun.js": "^10.2.3", "method-override": "^3.0.0", "node-fetch": "^3.3.2", "nodemailer-mailgun-transport": "^2.1.5", "nodemon": "^3.1.4", "ts-node": "^10.9.2" }, "devDependencies": { "typescript": "^5.5.4", "prettier": "^3.3.3" }, "engines": { "node": ">=20.11.1" } }
错误信息
<--- Last few GCs ---> Aug 27 04:11:56 ip-172-31-39-135 loopfive_services[51750]: [51750:0x5b6f280] 13591 ms: Scavenge (reduce) 477.6 (486.1) -> 477.2 (486.4) MB, 5.85 / 0.00 ms (average m> Aug 27 04:11:56 ip-172-31-39-135 loopfive_services[51750]: [51750:0x5b6f280] 13769 ms: Mark-Compact (reduce) 477.9 (486.4) -> 477.7 (487.4) MB, 95.09 / 0.01 ms (+ 30> Aug 27 04:11:56 ip-172-31-39-135 loopfive_services[51750]: <--- JS stacktrace ---> Aug 27 04:11:56 ip-172-31-39-135 loopfive_services[51750]: FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory Aug 27 04:11:56 ip-172-31-39-135 loopfive_services[51750]: ----- Native stack trace ----- Aug 27 04:11:56 ip-172-31-39-135 loopfive_services[51750]: 1: 0xb86ecf node::OOMErrorHandler(char const*, v8::OOMDetails const&) [node] Aug 27 04:11:56 ip-172-31-39-135 loopfive_services[51750]: 2: 0xef74d0 v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, v8::OOMDetails const&) [node] Aug 27 04:11:56 ip-172-31-39-135 loopfive_services[51750]: 3: 0xef77b7 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, v8::OOMDetails con> Aug 27 04:11:56 ip-172-31-39-135 loopfive_services[51750]: 4: 0x1109355 [node] Aug 27 04:11:56 ip-172-31-39-135 loopfive_services[51750]: 5: 0x11211d8 v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectio> Aug 27 04:11:56 ip-172-31-39-135 loopfive_services[51750]: 6: 0x10f72f1 v8::internal::HeapAllocator::AllocateRawWithLightRetrySlowPath(int, v8::internal::AllocationType> Aug 27 04:11:56 ip-172-31-39-135 loopfive_services[51750]: 7: 0x10f8485 v8::internal::HeapAllocator::AllocateRawWithRetryOrFailSlowPath(int, v8::internal::AllocationTyp> Aug 27 04:11:56 ip-172-31-39-135 loopfive_services[51750]: 8: 0x10d5ad6 v8::internal::Factory::NewFillerObject(int, v8::internal::AllocationAlignment, v8::internal::All> Aug 27 04:11:56 ip-172-31-39-135 loopfive_services[51750]: 9: 0x1531906 v8::internal::Runtime_AllocateInYoungGeneration(int, unsigned long*, v8::internal::Isolate*) [no> Aug 27 04:11:56 ip-172-31-39-135 loopfive_services[51750]: 10: 0x196aef6 [node] Aug 27 04:11:57 ip-172-31-39-135 loopfive_services[51749]: Aborted (core dumped)
解决方案
1. 增加Node.js内存限制
EC2实例(如t2.micro)默认内存较小,ts-node运行时加上googleapis库初始化的内存开销容易触发溢出。修改package.json的启动脚本,给Node.js分配更多内存:
"start": "nodemon --max-old-space-size=1024 index.ts"
生产环境建议先编译TypeScript为JavaScript再运行,进一步降低内存开销:
"build": "tsc", "start:prod": "node --max-old-space-size=1024 dist/index.js"
参数--max-old-space-size=1024代表分配1GB内存,可根据实例内存调整(比如t2.small设2048)。
2. 延迟初始化OAuth2Client
不要在全局作用域直接实例化OAuth2Client,改为在需要使用的路由中懒加载,避免启动时一次性加载所有Google API相关资源:
// googleApiRoutes.ts import { google } from 'googleapis'; import express from 'express'; const router = express.Router(); // 懒加载OAuth2Client let oauthClient: google.auth.OAuth2 | null = null; const getOAuthClient = () => { if (!oauthClient) { oauthClient = new google.auth.OAuth2( process.env.GOOGLE_APIS_CLIENT_ID, process.env.GOOGLE_APIS_CLIENT_SECRET, process.env.GOOGLE_API_REDIRECT_URL ); } return oauthClient; }; // 在路由中使用 router.get('/auth-url', (req, res) => { const client = getOAuthClient(); const authUrl = client.generateAuthUrl({ access_type: 'offline', scope: ['email', 'profile'] }); res.send({ authUrl }); }); module.exports = router;
3. 优化运行环境
- 生产环境禁用nodemon:nodemon是开发工具,会额外占用内存,生产环境直接运行编译后的JS文件。
- 检查EC2实例内存:执行
free -m查看内存使用情况,如果剩余内存不足,考虑升级实例规格(比如从t2.micro升到t2.small)。 - 清理无用依赖:检查package.json,移除不需要的依赖,减少启动时加载的资源量。
内容的提问来源于stack exchange,提问作者IlyesHadji
相关产品推荐
相关产品推荐

