我正在Mac上使用Node v8.12.0(尽管我已经在Node 9.x版本以及Linux上看到了此问题)。
我正在开发Angular 6应用,并且正在运行带有--watch
标志的开发版本。手表将运行并且可以重建应用程序大约4或5次,然后Node崩溃,并显示以下输出:
<--- Last few GCs --->
[34201:0x104000000] 273927 ms: Mark-sweep 1309.4 (1430.5) -> 1309.2 (1431.0) MB, 1296.0 / 0.0 ms allocation failure GC in old space requested
[34201:0x104000000] 275358 ms: Mark-sweep 1309.2 (1431.0) -> 1309.2 (1424.0) MB, 1430.8 / 0.0 ms last resort GC in old space requested
[34201:0x104000000] 276946 ms: Mark-sweep 1309.2 (1424.0) -> 1309.2 (1423.5) MB, 1587.7 / 0.0 ms last resort GC in old space requested
<--- JS stacktrace --->
==== JS stack trace =========================================
Security context: 0x1c5f3a825879 <JSObject>
1: fromString(aka fromString) [buffer.js:~298] [pc=0x2234a1ca140b](this=0x1c5ffcc022d1 <undefined>,string=0x1c5f6f8dffa1 <Very long string[784654]>,encoding=0x1c5ffcc022d1 <undefined>)
2: from [buffer.js:177] [bytecode=0x1c5f43e4aac9 offset=11](this=0x1c5f8a5b5c51 <JSFunction Buffer (sfi = 0x1c5f3a87e159)>,value=0x1c5f6f8dffa1 <Very long string[784654]>,encodingOrOffset=0x1c5ffcc022d1 <u...
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
1: node::Abort() [/usr/local/bin/node]
2: node::FatalException(v8::Isolate*, v8::Local<v8::Value>, v8::Local<v8::Message>) [/usr/local/bin/node]
3: v8::internal::V8::FatalProcessOutOfMemory(char const*, bool) [/usr/local/bin/node]
4: v8::internal::Factory::NewRawTwoByteString(int, v8::internal::PretenureFlag) [/usr/local/bin/node]
5: v8::internal::String::SlowFlatten(v8::internal::Handle<v8::internal::ConsString>, v8::internal::PretenureFlag) [/usr/local/bin/node]
6: v8::String::WriteUtf8(char*, int, int*, int) const [/usr/local/bin/node]
7: node::StringBytes::Write(v8::Isolate*, char*, unsigned long, v8::Local<v8::Value>, node::encoding, int*) [/usr/local/bin/node]
8: node::Buffer::New(v8::Isolate*, v8::Local<v8::String>, node::encoding) [/usr/local/bin/node]
9: node::Buffer::(anonymous namespace)::CreateFromString(v8::FunctionCallbackInfo<v8::Value> const&) [/usr/local/bin/node]
10: 0x2234a02d4067
11: 0x2234a1ca140b
12: 0x2234a023d1d6
13: 0x2234a018535f
我也尝试添加--max_old_space_size=12000
,但似乎没有任何区别。我不确定在哪里寻找问题的原因,或者如何开始在Node中调试。任何帮助将不胜感激!
某些背景:那是带有弹出配置的Angular 5应用程序,并且我已经使用相同的配置将其更新为Angular 6,并且应用程序本身按预期运行。只是从更新到Angular 6以来,这个问题才开始出现。
作为参考,这是package.json的依赖项和devDependency部分:
"dependencies": {
"@angular/animations": "6.1.10",
"@angular/cdk": "6.4.7",
"@angular/common": "6.1.10",
"@angular/compiler": "6.1.10",
"@angular/core": "6.1.10",
"@angular/forms": "6.1.10",
"@angular/http": "6.1.10",
"@angular/material": "6.4.7",
"@angular/platform-browser": "6.1.10",
"@angular/platform-browser-dynamic": "6.1.10",
"@angular/router": "6.1.10",
"@ng-idle/core": "6.0.0-beta.3",
"@ng-idle/keepalive": "6.0.0-beta.3",
"@ngrx/effects": "6.1.2",
"@ngrx/entity": "6.1.2",
"@ngrx/router-store": "6.1.2",
"@ngrx/store": "6.1.2",
"@ngrx/store-devtools": "6.1.2",
"@swimlane/ngx-datatable": "14.0.0",
"@types/crypto-js": "3.1.37",
"@types/moment": "2.13.0",
"angular2-toaster": "6.1.0",
"angulartics2": "7.2.0",
"core-js": "2.5.7",
"crypto-js": "3.1.9-1",
"hammerjs": "2.0.8",
"immutable": "3.8.2",
"jquery": "2.2.4",
"moment": "2.19.1",
"ng2-charts": "1.6.0",
"ngx-zendesk-webwidget": "0.1.3",
"node-waves": "0.7.6",
"normalize.css": "3.0.3",
"rxjs": "6.3.3",
"sass": "1.15.1",
"zone.js": "0.8.26"
},
"devDependencies": {
"@angular-builders/custom-webpack": "7.0.0",
"@angular-devkit/build-angular": "0.11.0",
"@angular/cli": "7.0.6",
"@angular/compiler-cli": "6.1.10",
"@angular/language-service": "6.1.10",
"@types/jasmine": "2.5.53",
"@types/jasminewd2": "2.0.2",
"@types/node": "6.0.60",
"autoprefixer": "9.3.1",
"chromedriver": "2.38.2",
"clean-webpack-plugin": "1.0.0",
"codelyzer": "4.5.0",
"copy-webpack-plugin": "4.6.0",
"css-loader": "1.0.1",
"cssnano": "4.1.7",
"exports-loader": "0.7.0",
"file-loader": "2.0.0",
"istanbul-instrumenter-loader": "2.0.0",
"jasmine-allure-reporter": "1.0.2",
"jasmine-core": "2.6.2",
"jasmine-marbles": "0.4.0",
"jasmine-spec-reporter": "4.2.1",
"karma": "3.0.0",
"karma-chrome-launcher": "2.2.0",
"karma-cli": "1.0.1",
"karma-coverage-istanbul-reporter": "2.0.1",
"karma-jasmine": "1.1.2",
"karma-jasmine-html-reporter": "0.2.2",
"karma-spec-reporter": "0.0.32",
"lint-staged": "8.1.0",
"loader-utils": "1.1.0",
"mini-css-extract-plugin": "0.4.5",
"npm-run-all": "4.1.5",
"postcss-custom-properties": "8.0.9",
"postcss-loader": "3.0.0",
"postcss-url": "8.0.0",
"pre-commit": "1.2.2",
"process": "0.11.10",
"protractor": "5.4.1",
"protractor-console": "3.0.0",
"protractor-jasmine2-html-reporter": "0.0.7",
"puppeteer": "1.6.0",
"raw-loader": "0.5.1",
"rxjs-tslint": "0.1.5",
"sass-loader": "7.1.0",
"selenium-server-standalone-jar": "3.8.1",
"source-map-loader": "0.2.4",
"style-loader": "0.23.1",
"stylelint": "9.6.0",
"stylelint-config-recommended": "2.1.0",
"ts-mockito": "2.3.1",
"ts-node": "3.2.0",
"tslint": "5.7.0",
"typescript": "2.9.2",
"uglifyjs-webpack-plugin": "2.0.1",
"url-loader": "1.1.2",
"webpack": "4.24.0",
"webpack-bundle-analyzer": "3.0.3",
"webpack-cli": "3.1.2",
"webpack-concat-plugin": "3.0.0",
"webpack-dev-server": "3.1.10",
"webpack-filter-warnings-plugin": "^1.2.1",
"yargs": "8.0.1"
}
最后,这是我正在使用的自定义Webpack配置(在Angular 5中完美运行):
const path = require('path');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const autoprefixer = require('autoprefixer');
const postcssUrl = require('postcss-url');
const cssnano = require('cssnano');
const customProperties = require('postcss-custom-properties');
const webpack = require('webpack');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const { NoEmitOnErrorsPlugin, SourceMapDevToolPlugin, NormalModuleReplacementPlugin } = require('webpack');
const { AngularCompilerPlugin } = require('@ngtools/webpack');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const FilterWarningsPlugin = require('webpack-filter-warnings-plugin');
const CircularDependencyPlugin = require('circular-dependency-plugin');
const ProgressPlugin = require('webpack/lib/ProgressPlugin');
const postcssPlugins = function (env) {
// safe settings based on: https://github.com/ben-eb/cssnano/issues/358#issuecomment-283696193
const importantCommentRe = /@preserve|@license|[@#]\s*source(?:Mapping)?URL|^!/i;
const baseHref = '';
const deployUrl = '';
const minimizeOptions = {
preset: [
'default',
{
mergeLonghand: false,
discardComments: { remove: (comment) => !importantCommentRe.test(comment) }
}
]
};
return [
postcssUrl({
url: (URL) => {
// Only convert root relative URLs, which CSS-Loader won't process into require().
if (!URL.url.startsWith('/') || URL.url.startsWith('//')) {
return URL.url;
}
if (deployUrl.match(/:\/\//)) {
// If deployUrl contains a scheme, ignore baseHref use deployUrl as is.
return `${deployUrl.replace(/\/$/, '')}${URL.url}`;
}
else if (baseHref.match(/:\/\//)) {
// If baseHref contains a scheme, include it as is.
return baseHref.replace(/\/$/, '') +
`/${deployUrl}/${URL.url}`.replace(/\/\/+/g, '/');
}
else {
// Join together base-href, deploy-url and the original URL.
// Also dedupe multiple slashes into single ones.
return `/${baseHref}/${deployUrl}/${URL.url}`.replace(/\/\/+/g, '/');
}
}
}),
autoprefixer(),
customProperties({ preserve: true })
].concat(env === 'prod' ? [cssnano(minimizeOptions)] : []);
};
const builder = (customer, prodEnv) => {
let plugins = [
new ProgressPlugin(),
new NoEmitOnErrorsPlugin(),
new FilterWarningsPlugin({
exclude: /System.import/
}),
new CleanWebpackPlugin(['target/classes/static/' + customer]),
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[id].css'
}),
new CopyWebpackPlugin([
{
context: 'src/main/angular',
to: '',
from: {
glob: 'assets/**/*',
dot: true
}
},
{
context: 'src/main/angular',
to: '',
from: {
glob: 'favicon.ico',
dot: true
}
}
], {
ignore: [
'.gitkeep',
'**/.DS_Store'
],
debug: 'warning'
}),
//Replace the actual environment file with the correct one passed in via env args
new NormalModuleReplacementPlugin(/(.*)\environments\/environment(\.*)/, function(resource) {
resource.request = resource.request.replace('environments/environment',
`environments/${customer}/environment.${prodEnv}`);
}),
//Replace the actual chart-colors file with the correct one based on customer
new NormalModuleReplacementPlugin(/(.*)\environments\/chart-colors.json/, function(resource) {
resource.request = resource.request.replace('environments/chart-colors.json',
`environments/${customer}/chart-colors.json`);
}),
//Replace the actual lang file with the correct one based on customer
new NormalModuleReplacementPlugin(/(.*)\environments\/lang.json/, function(resource) {
resource.request = resource.request.replace('environments/lang.json',
`environments/${customer}/lang.json`);
}),
//Replace the actual scss file with the correct one based on customer
new NormalModuleReplacementPlugin(/(.*)\environments\/styles.scss/, function(resource) {
resource.request = resource.request.replace('environments/styles.scss',
`environments/${customer}/styles.scss`);
}),
new AngularCompilerPlugin({
mainPath: 'main.ts',
platform: 0,
sourceMap: (prodEnv === 'dev') ? true : false,
tsConfigPath: 'src/main/angular/tsconfig.app.json',
skipCodeGeneration: true,
compilerOptions: {}
}),
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
"window.jQuery": 'jquery',
Hammer: 'hammerjs/hammer'
})
];
let devPlugins = [
new CircularDependencyPlugin({
exclude: /(\\|\/)node_modules(\\|\/)/,
failOnError: false
}),
new SourceMapDevToolPlugin({
filename: '[file].map[query]',
moduleFilenameTemplate: '[resource-path]',
fallbackModuleFilenameTemplate: '[resource-path]?[hash]',
sourceRoot: 'webpack:///',
exclude: ['vendor.js']
}),
new BundleAnalyzerPlugin({
generateStatsFile: true
})
];
let prodPlugins = [
new UglifyJsPlugin({
parallel: true,
sourceMap: false
})
];
plugins = prodEnv === 'dev'
? plugins.concat(devPlugins)
: plugins.concat(prodPlugins);
return {
resolve: {
extensions: [
'.ts',
'.js'
],
modules: [
'./node_modules'
],
symlinks: true,
alias: {
"rxjs/" : './node_modules/rxjs/_esm2015/'
},
mainFields: [
'browser',
'module',
'main'
]
},
resolveLoader: {
modules: [
'./node_modules'
]
},
entry: {
main: [
'./src/main/angular/main.ts'
],
polyfills: [
'./src/main/angular/polyfills.ts'
]
},
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
chunks: 'initial',
test: path.join(process.cwd(), 'node_modules'),
name: 'vendor',
enforce: true,
filename: 'vendor.chunk.js'
}
}
}
},
output: {
path: path.join(process.cwd(), 'target', 'classes', 'static', customer),
filename: '[name].bundle.js',
chunkFilename: '[id].chunk.js',
crossOriginLoading: false
},
module: {
rules: [
{
test: /\.html$/,
loader: 'raw-loader'
},
{
test: /\.(eot|svg|cur)$/,
loader: 'file-loader',
options: {
name: '[name].[hash:20].[ext]',
limit: 10000
}
},
{
test: /\.(jpg|png|webp|gif|otf|ttf|woff|woff2|ani)$/,
loader: 'url-loader',
options: {
name: '[name].[hash:20].[ext]',
limit: 10000
}
},
{
test: /\.css$/,
use: [
'exports-loader?module.exports.toString()',
{
loader: 'css-loader',
options: {
sourceMap: false,
importLoaders: 1
}
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: postcssPlugins(prodEnv)
}
}
]
},
{
test: /\.css$/,
include: [
path.join(process.cwd(), `src/main/angular/environments/${customer}/styles.scss`)
],
use: [
'style-loader',
{
loader: 'css-loader',
options: {
sourceMap: false,
importLoaders: 1
}
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: postcssPlugins(prodEnv)
}
}
]
},
{
test: /\.scss$/,
include: [
path.join(process.cwd(), `src/main/angular/environments/${customer}/styles.scss`)
],
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
sourceMap: false,
importLoaders: 1
}
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: postcssPlugins(prodEnv)
}
},
{
loader: 'sass-loader',
options: {
sourceMap: false,
precision: 8,
includePaths: [path.join(process.cwd(), 'src', 'main', 'angular')]
}
}
]
},
{
test: /\.ts$/,
loader: '@ngtools/webpack'
}
]
},
mode: (prodEnv === 'prod') ? 'production' : 'development',
plugins: plugins,
node: {
fs: 'empty',
global: true,
crypto: 'empty',
tls: 'empty',
net: 'empty',
process: true,
module: false,
clearImmediate: false,
setImmediate: false
},
devServer: {
historyApiFallback: true
},
watchOptions: {
aggregateTimeout: 500
}
};
};
module.exports = {
build: builder
}
答案 0 :(得分:3)
这被称为内存泄漏,它表示您试图保留大量内存!
请注意,分配更多的内存(--max_new_space_size
和/或--max_old_space_size
)不会解决主要问题,尽管可能有助于继续处理消耗内存的应用程序。
如您所知,在javascript应用程序中,build是一个导出小型捆绑包的过程,这些捆绑包来自于依赖项和您的个人代码。在某些情况下,依赖关系(不匹配版本)之间的兼容性问题可能会保留更多的内存!例如,用户发现了lodash v4.14.70 is not compatible with TS 2.7 out of the box。尽管您不使用 lodash ,但可以预期会出现这种情况。
此外,您必须熟悉cases in javascript where memory leaks happen,然后弄清应用程序中使用了过多的内存。我也建议您Record Heap Snapshots。我列出了一些可能发生内存泄漏的情况(一目了然):
由于您的应用程序在更新到Angular6之前运行良好,因此主要的影响来自您的新依赖项。我认为这对于从第一步中清除未使用的依赖项中的项目很有必要,也许可以使用dependency-check之类的工具(我从未测试过)。 然后尝试再次使用Angular Update Guide将项目从Angular5迁移到Angular6 。 然后检查相关性之间的兼容性。在撰写此答案时,我还没有找到任何工具来查找兼容版本,但是作为一个技巧,您可以使用在相同时间段(并发)发布的版本。
答案 1 :(得分:3)
我们已经看到Angular 5有时也会发生这种情况。我们的解决方案(解决方法?)是使用max_old_space_size
参数运行ng服务。
node --max_old_space_size=8192 node_modules/@angular/cli/bin/ng serve --aot
设置--max_old_space_size=8192
对我来说很有效,但是对于部分开发人员来说,这确实是一个很好的解决方案。对于另一个,我们可以尝试其他解决方案
这是我的解决方案,它要求人们在Windows上使用git bash作为终端,但是如果需要的话,它很容易更改(只需使用cmd文件即可):
在我的项目根目录中,有一个名为scripts的文件夹,其中有一个名为ng.sh的文件,该文件是node_modules/.bin/ng
的副本,但允许使用更多的 RAM >
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" --max_old_space_size=8192 "./node_modules/@angular/cli/bin/ng" "$@"
ret=$?
else
node --max_old_space_size=8192 "./node_modules/@angular/cli/bin/ng" "$@"
ret=$?
fi
exit $ret
然后在我的package.json
中做
"scripts": {
"build-prod": "bash ./scripts/ng.sh build --prod --aot --env=prod"
}