为React Native捆绑js时如何防止节点运行内存不足
How to prevent node from running out of memory when bundling js for React Native
使用 ClojureScript 为 React Native 捆绑 js 时出现以下错误。似乎节点在捆绑 javascript 包时内存不足。使用 ClojureScript 时更可能发生这种情况,因为生成的 js 文件通常比 vanilla js 大。
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
<--- Last few GCs --->
152689 ms: Mark-sweep 1369.3 (1434.8) -> 1362.8 (1434.8) MB, 2794.5 / 0 ms [allocation failure] [GC in old space requested].
155498 ms: Mark-sweep 1362.8 (1434.8) -> 1362.9 (1434.8) MB, 2808.4 / 0 ms [allocation failure] [GC in old space requested].
158508 ms: Mark-sweep 1362.9 (1434.8) -> 1362.8 (1434.8) MB, 3010.8 / 0 ms [last resort gc].
161189 ms: Mark-sweep 1362.8 (1434.8) -> 1362.8 (1434.8) MB, 2680.5 / 0 ms [last resort gc].
<--- JS stacktrace --->
==== JS stack trace =========================================
Security context: 0xd4b9fdc9e59 <JS Object>
1: visitQueue [/Users/myproj/node_modules/babel-traverse/lib/context.js:~130] [pc=0x3e89a3f7bd28] (this=0x24a5ec659101 <a TraversalContext with map 0x157972399611>,queue=0x24a5ec659149 <JS Array[1]>)
2: node [/Users/myproj/node_modules/babel-traverse/lib/index.js:~150] [pc=0x3e89a3e4f23a] (this=0x387a6b7f4301 <JS Function traverse (SharedFunction...
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
<--- Last few GCs --->
238422 ms: Mark-sweep 1364.8 (1434.8) -> 1364.8 (1434.8) MB, 3377.7 / 0 ms [allocation failure] [GC in old space requested].
241834 ms: Mark-sweep 1364.8 (1434.8) -> 1364.8 (1434.8) MB, 3412.3 / 0 ms [allocation failure] [GC in old space requested].
245313 ms: Mark-sweep 1364.8 (1434.8) -> 1364.8 (1434.8) MB, 3478.7 / 0 ms [last resort gc].
248639 ms: Mark-sweep 1364.8 (1434.8) -> 1364.8 (1434.8) MB, 3326.4 / 0 ms [last resort gc].
<--- JS stacktrace --->
==== JS stack trace =========================================
Security context: 0x266dabec9e59 <JS Object>
1: new constructor(aka NodePath) [/Users/myproj/node_modules/babel-traverse/lib/path/index.js:~61] [pc=0x108980041705] (this=0x1cedf9a7ef69 <a NodePath with map 0x3182f379cf21>,hub=0x266dabe04189 <undefined>,parent=0x3d43337ab49 <a Node with map 0x3182f3798489>)
3: get [/Users/myproj/node_modules/babel-traverse/lib/path/index.js:~87] [pc=0x10898...
[node-haste] Encountered an error while persisting cache:
> Error: Uncaught error in the transformer worker: /Users/myproj/node_modules/react-native/packager/transformer.js
> at _transform.then.catch.error (/Users/myproj/node_modules/react-native/packager/react-packager/src/JSTransformer/index.js:99:31)
> at tryCallOne (/Users/myproj/node_modules/promise/lib/core.js:37:12)
> at /Users/myproj/node_modules/promise/lib/core.js:123:15
> at flush (/Users/myproj/node_modules/asap/raw.js:50:29)
> at _combinedTickCallback (internal/process/next_tick.js:67:7)
> at process._tickCallback (internal/process/next_tick.js:98:9)
/Users/myproj/node_modules/promise/lib/done.js:10
throw err;
^
Error: Uncaught error in the transformer worker: /Users/myproj/node_modules/react-native/packager/transformer.js
at _transform.then.catch.error (/Users/myproj/node_modules/react-native/packager/react-packager/src/JSTransformer/index.js:99:31)
at tryCallOne (/Users/myproj/node_modules/promise/lib/core.js:37:12)
at /Users/myproj/node_modules/promise/lib/core.js:123:15
at flush (/Users/myproj/node_modules/asap/raw.js:50:29)
at _combinedTickCallback (internal/process/next_tick.js:67:7)
at process._tickCallback (internal/process/next_tick.js:98:9)
Command /bin/sh failed with exit code 1
iOS 的解决方案是编辑以下文件:ios/YourProjectName.xcodeproj/project.pbxproj
并更改以下行 (~600)
shellScript = "export NODE_BINARY=node\n../node_modules/react-native/packager/react-native-xcode.sh";
至
shellScript = "export NODE_BINARY='node --max_old_space_size=4092'\n../node_modules/react-native/packager/react-native-xcode.sh";
另一种解决方法是通过为生产构建设置 --dev true
来禁用优化。这有性能缺陷,但根据我的经验,它们是可以接受的。开发模式还启用了一些运行时检查。您可以通过更改捆绑输出顶部的 DEV 常量来禁用它们,如下所示:
#!/usr/bin/env python
# Patch jsbundle to set __DEV__ to false
import sys, re
print(re.sub(r'__DEV__\s*=\s*true;', "__DEV__=false;",
sys.stdin.read()))
我找到了在重生项目中生成签名 APK 的方法。
为此,我们必须在 node_modules/react-native/react.gradle
中编辑文件
更改此文件中的第 84 行。
来自
commandLine(*nodeExecutableAndArgs, "node_modules/react-native/local-cli/cli.js", "bundle", "--platform", "android", "--dev", "${devEnabled}",
"--reset-cache", "--entry-file", entryFile, "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir, *extraPackagerArgs)
对此
commandLine(*nodeExecutableAndArgs, "--max-old-space-size=4096", "node_modules/react-native/local-cli/cli.js", "bundle", "--platform", "android", "--dev", "${devEnabled}",
"--reset-cache", "--entry-file", entryFile, "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir, *extraPackagerArgs)
要创建生产版本,您必须使用
lein prod-build
编译 ClojureScript 后使用此命令:
cd android && ./gradlew assembleRelease
生成的 APK 可以在 android/app/build/outputs/apk/app-release.apk
下找到,可以分发了。
对于android,这也可以在android/app/build.gradle中设置,方法是添加:
project.ext.react = [
// override which node gets called and with what additional arguments
nodeExecutableAndArgs: ["node", "--max-old-space-size=4096"]
]
请注意,必须将其添加到以下行上方:
apply from: "../../node_modules/react-native/react.gradle"
对于 iOS
,使用 react-native 0.59.0 通过编辑 ios/YourProjectName.xcodeproj/project.pbxproj
工作
这一行
shellScript = "export NODE_BINARY=node\n../node_modules/react-native/packager/react-native-xcode.sh";
和
shellScript = "export NODE_OPTIONS=--max_old_space_size=4096\n../node_modules/react-native/scripts/react-native-xcode.sh";
使用 ClojureScript 为 React Native 捆绑 js 时出现以下错误。似乎节点在捆绑 javascript 包时内存不足。使用 ClojureScript 时更可能发生这种情况,因为生成的 js 文件通常比 vanilla js 大。
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
<--- Last few GCs --->
152689 ms: Mark-sweep 1369.3 (1434.8) -> 1362.8 (1434.8) MB, 2794.5 / 0 ms [allocation failure] [GC in old space requested].
155498 ms: Mark-sweep 1362.8 (1434.8) -> 1362.9 (1434.8) MB, 2808.4 / 0 ms [allocation failure] [GC in old space requested].
158508 ms: Mark-sweep 1362.9 (1434.8) -> 1362.8 (1434.8) MB, 3010.8 / 0 ms [last resort gc].
161189 ms: Mark-sweep 1362.8 (1434.8) -> 1362.8 (1434.8) MB, 2680.5 / 0 ms [last resort gc].
<--- JS stacktrace --->
==== JS stack trace =========================================
Security context: 0xd4b9fdc9e59 <JS Object>
1: visitQueue [/Users/myproj/node_modules/babel-traverse/lib/context.js:~130] [pc=0x3e89a3f7bd28] (this=0x24a5ec659101 <a TraversalContext with map 0x157972399611>,queue=0x24a5ec659149 <JS Array[1]>)
2: node [/Users/myproj/node_modules/babel-traverse/lib/index.js:~150] [pc=0x3e89a3e4f23a] (this=0x387a6b7f4301 <JS Function traverse (SharedFunction...
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
<--- Last few GCs --->
238422 ms: Mark-sweep 1364.8 (1434.8) -> 1364.8 (1434.8) MB, 3377.7 / 0 ms [allocation failure] [GC in old space requested].
241834 ms: Mark-sweep 1364.8 (1434.8) -> 1364.8 (1434.8) MB, 3412.3 / 0 ms [allocation failure] [GC in old space requested].
245313 ms: Mark-sweep 1364.8 (1434.8) -> 1364.8 (1434.8) MB, 3478.7 / 0 ms [last resort gc].
248639 ms: Mark-sweep 1364.8 (1434.8) -> 1364.8 (1434.8) MB, 3326.4 / 0 ms [last resort gc].
<--- JS stacktrace --->
==== JS stack trace =========================================
Security context: 0x266dabec9e59 <JS Object>
1: new constructor(aka NodePath) [/Users/myproj/node_modules/babel-traverse/lib/path/index.js:~61] [pc=0x108980041705] (this=0x1cedf9a7ef69 <a NodePath with map 0x3182f379cf21>,hub=0x266dabe04189 <undefined>,parent=0x3d43337ab49 <a Node with map 0x3182f3798489>)
3: get [/Users/myproj/node_modules/babel-traverse/lib/path/index.js:~87] [pc=0x10898...
[node-haste] Encountered an error while persisting cache:
> Error: Uncaught error in the transformer worker: /Users/myproj/node_modules/react-native/packager/transformer.js
> at _transform.then.catch.error (/Users/myproj/node_modules/react-native/packager/react-packager/src/JSTransformer/index.js:99:31)
> at tryCallOne (/Users/myproj/node_modules/promise/lib/core.js:37:12)
> at /Users/myproj/node_modules/promise/lib/core.js:123:15
> at flush (/Users/myproj/node_modules/asap/raw.js:50:29)
> at _combinedTickCallback (internal/process/next_tick.js:67:7)
> at process._tickCallback (internal/process/next_tick.js:98:9)
/Users/myproj/node_modules/promise/lib/done.js:10
throw err;
^
Error: Uncaught error in the transformer worker: /Users/myproj/node_modules/react-native/packager/transformer.js
at _transform.then.catch.error (/Users/myproj/node_modules/react-native/packager/react-packager/src/JSTransformer/index.js:99:31)
at tryCallOne (/Users/myproj/node_modules/promise/lib/core.js:37:12)
at /Users/myproj/node_modules/promise/lib/core.js:123:15
at flush (/Users/myproj/node_modules/asap/raw.js:50:29)
at _combinedTickCallback (internal/process/next_tick.js:67:7)
at process._tickCallback (internal/process/next_tick.js:98:9)
Command /bin/sh failed with exit code 1
iOS 的解决方案是编辑以下文件:ios/YourProjectName.xcodeproj/project.pbxproj
并更改以下行 (~600)
shellScript = "export NODE_BINARY=node\n../node_modules/react-native/packager/react-native-xcode.sh";
至
shellScript = "export NODE_BINARY='node --max_old_space_size=4092'\n../node_modules/react-native/packager/react-native-xcode.sh";
另一种解决方法是通过为生产构建设置 --dev true
来禁用优化。这有性能缺陷,但根据我的经验,它们是可以接受的。开发模式还启用了一些运行时检查。您可以通过更改捆绑输出顶部的 DEV 常量来禁用它们,如下所示:
#!/usr/bin/env python
# Patch jsbundle to set __DEV__ to false
import sys, re
print(re.sub(r'__DEV__\s*=\s*true;', "__DEV__=false;",
sys.stdin.read()))
我找到了在重生项目中生成签名 APK 的方法。
为此,我们必须在 node_modules/react-native/react.gradle
更改此文件中的第 84 行。 来自
commandLine(*nodeExecutableAndArgs, "node_modules/react-native/local-cli/cli.js", "bundle", "--platform", "android", "--dev", "${devEnabled}",
"--reset-cache", "--entry-file", entryFile, "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir, *extraPackagerArgs)
对此
commandLine(*nodeExecutableAndArgs, "--max-old-space-size=4096", "node_modules/react-native/local-cli/cli.js", "bundle", "--platform", "android", "--dev", "${devEnabled}",
"--reset-cache", "--entry-file", entryFile, "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir, *extraPackagerArgs)
要创建生产版本,您必须使用
lein prod-build
编译 ClojureScript 后使用此命令:
cd android && ./gradlew assembleRelease
生成的 APK 可以在 android/app/build/outputs/apk/app-release.apk
下找到,可以分发了。
对于android,这也可以在android/app/build.gradle中设置,方法是添加:
project.ext.react = [
// override which node gets called and with what additional arguments
nodeExecutableAndArgs: ["node", "--max-old-space-size=4096"]
]
请注意,必须将其添加到以下行上方:
apply from: "../../node_modules/react-native/react.gradle"
对于 iOS
,使用 react-native 0.59.0 通过编辑 ios/YourProjectName.xcodeproj/project.pbxproj
这一行
shellScript = "export NODE_BINARY=node\n../node_modules/react-native/packager/react-native-xcode.sh";
和
shellScript = "export NODE_OPTIONS=--max_old_space_size=4096\n../node_modules/react-native/scripts/react-native-xcode.sh";