
如果你的 Flutter 版本号小于等于 2.5.3 或大于等于 3.0.5,以下描述的问题将不会发生在你的应用中,但是我相信大部分应用都会命中此区间。事情发生在最近,我们的应用(稿定设计)新上线的 iOS 版本崩溃数据飙升。根据崩溃日志和用户反馈,大部分新增崩溃都来自于同一个原因:内存不足。有的直接变成 OOM,不易排查。有的则是申请内存失败,导致后续逻辑错误的崩溃。结合「处处开花,多点爆破」的情况来看,应该是某种偏底层的内存管理问题。这就有点挠头了,因为这个版本并没有做什么内存相关的改动。于是我采取了二分法,花了两个小时试了版本中所有 PR,发现罪魁祸首是 Flutter 版本升级:2.5.3 → 2.10.。那么问题就转化为:Flutter 在 2.5.3 → 2.10. 中做了什么改动,导致了内存崩溃问题。
对比内存情况可以得出一个结论:升级前内存容忍度更高,1.2G 峰值都没问题;升级后内存容忍度更低,1.1G 峰值就崩溃。这让我联想到了「压缩内存」:iOS 系统会在内存紧张的时候,把一部分不用的内存做压缩,以腾出内存空间。在需要读取这些压缩内存的时候,也需要先解压再读取。听起来很好的机制,为什么会出问题呢?有一个经典案例:
文中提到了几个关键点:客户投诉是第一生产力?于是我这个一行 Flutter 代码都没写过的人,就硬着头皮上了。在阅读了无数官方 / 民间文档之后,花了三天时间,硬是整出来了,在 Flutter Engine 中加上了自定义打印:
具体方案二是如何解决问题的,下文细说。碰巧的是,就在我们用方案二解决问题之时,方案一也迎来了曙光:Flutter 紧急发布了 3.0.5 版本,该版本中 Flutter Engine 关闭了内存压缩。于是,我们立刻升级尝试了一下,确实不会崩溃了,我们稍加适配,就上线了。目前根据线上数据反馈,内存崩溃问题已经完美解决。
$ git clone https://chromium.googlesource.com/chromium/tools/depot_tools.gitexport PATH=/path/to/depot_tools:$PATHsolutions = [
{
"managed": False,
"name": "src/flutter",
"url": "git@github.com:JPlay/engine.git@57d3bac3dd5cb5b0e464ab70e7bc8a0d8cf083ab",
"custom_deps": {},
"deps_file": "DEPS",
"safesync_url": "",
},
]$ cat /Users/JPlay/development/flutter/bin/internal/engine.version$ gclient sync --verbose
后续如果想再切换 engine 的分支,可以先进入 /src/flutter,然后执行:$ git reset --hard <commit id>
$ gclient sync --with_branch_heads --with_tags想简单了解一下 gn 和 ninja 的看这里[8],想详细了解 gn 的看这里,想详细了解 ninja 的看这里[9]值得一提的是,由于 Flutter 的编译产物是分平台的,我们目前主要需要的是 iOS 和 Android,这在 macOS 上都能搞定。在编译 iOS / Android 产物的同时,还需要而外编译一个 host 产物,这是因为我们需要编译出一个与当前版本对应的的 Dark SDK。因为代码版本、目标平台、目标架构都不唯一,所以接下来拿 iOS arm64 目标来举例,其他情况请酌情仿造。
usage: gn [-h] [--unoptimized] [--enable-unittests]
[--runtime-mode {debug,profile,release,jit_release}] [--interpreter]
[--dart-debug] [--no-dart-version-git-info] [--full-dart-debug]
[--target-os {android,ios,mac,linux,fuchsia,win,winuwp}] [--android]
[--android-cpu {arm,x64,x86,arm64}] [--ios] [--ios-cpu {arm,arm64}]
[--mac] [--mac-cpu {x64,arm64}] [--simulator] [--linux] [--fuchsia]
[--winuwp] [--linux-cpu {x64,x86,arm64,arm}]
[--fuchsia-cpu {x64,arm64}] [--windows-cpu {x64,arm64}]
[--simulator-cpu {x64,arm64}] [--arm-float-abi {hard,soft,softfp}]
[--goma] [--no-goma] [--xcode-symlinks] [--no-xcode-symlinks]
[--depot-tools DEPOT_TOOLS] [--lto] [--no-lto] [--clang]
[--no-clang] [--clang-static-analyzer] [--no-clang-static-analyzer]
[--target-sysroot TARGET_SYSROOT]
[--target-toolchain TARGET_TOOLCHAIN]
[--target-triple TARGET_TRIPLE]
[--operator-new-alignment OPERATOR_NEW_ALIGNMENT]
[--macos-enable-metal] [--enable-vulkan] [--enable-fontconfig]
[--enable-vulkan-validation-layers] [--enable-skshaper]
[--no-enable-skshaper] [--always-use-skshaper]
[--embedder-for-target] [--coverage] [--out-dir OUT_DIR]
[--full-dart-sdk] [--no-full-dart-sdk] [--ide IDE]
[--disable-desktop-embeddings] [--build-glfw-shell]
[--no-build-glfw-shell] [--build-embedder-examples]
[--no-build-embedder-examples] [--bitcode] [--stripped]
[--no-stripped] [--prebuilt-dart-sdk] [--no-prebuilt-dart-sdk]
[--fuchsia-target-api-level FUCHSIA_TARGET_API_LEVEL]
[--use-mallinfo2] [--asan] [--lsan] [--msan] [--tsan] [--ubsan]
[--trace-gn] [--verbose]| 参数名 | 说明 |
| --unoptimized | 默认是会进行优化(optimized)的,如果设置了不优化(unoptimized),则编译产物会留下一些方便调试的内容,比如:log, asset,dSYM 之类的 |
| --simulator | 接在平台之后,指定目标是否为模拟器 |
| --runtime-mode | 指定目标运行时模式,有 debug,profile,release,jit_release,详情看官方文档[10] |
| --ios-cpu / --android-cpu | 指定目标 CPU 架构,iOS 有 arm 和 arm64,Android 有 arm,x64,x86,arm64 |
| --ios --android | 指定目标平台,如果是编译 host,则不需要设置此参数 |
$ ./flutter/tools/gn --runtime-mode=debug --unoptimized
$ ./flutter/tools/gn --ios --runtime-mode=debug --unoptimized
$ ninja -C out/ios_debug_unopt && ninja -C out/host_debug_unopt
3. 修改 /src/third_party/dart/runtime/BUILD.gn。
以上修改都是为了解决「构建脚本默认把编译的 host 机器认为是 x64 架构」,而我们做的修改就是为了适配的 arm64 架构。由于编译脚本经常更新,所以以上修改方案可能只对当前 commit 生效,不过我总结出一些经验方便大家修改脚本:这个修改方案是我个人的临时方案,issue 中也有一些大神的其他思路,可以参考:github.com/flutter/flu…[13]
在 /src/flutter/shell/common/engine.cc 的 Run 方法中加入一个打印信息,这会让 engine 在启动的时候就打印这条信息。别忘了我们的初衷:在 /src/flutter/tools/gn 中关闭 iOS 的内存压缩,以解决内存问题:
修改完之后,重新编译一下:(这次是增量更新,很快):$ ninja -C out/ios_debug_unopt && ninja -C out/host_debug_unopt$ flutter run --local-engine-src-path=/path/to/engine/src/ --local-engine=ios_debug_unopt
应用成功运行了起来,并且输出了我们自定义的信息。到此我们取得了阶段性的成功,已经把我们修改的代码成功在 Flutter 项目中运行起来了。$ flutter run --local-engine-src-path=/path/to/engine/src/ --local-engine=ios_debug_unopt
接着把 /src/out/ios_debug_unopt/flutter_engine.xcodeproj 拖到 Runner 项目中:
找个会运行到的地方下个断点,比如 FlutterAppDelegate.mm 中 - init 方法。运行项目:
断点成功,接着就可以愉快地调试了。作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代
我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po
尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub
为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar
当我在Rails控制台中按向上或向左箭头时,出现此错误:irb(main):001:0>/Users/me/.rvm/gems/ruby-2.0.0-p247/gems/rb-readline-0.4.2/lib/rbreadline.rb:4269:in`blockin_rl_dispatch_subseq':invalidbytesequenceinUTF-8(ArgumentError)我使用rvm来管理我的ruby安装。我正在使用=>ruby-2.0.0-p247[x86_64]我使用bundle来管理我的gem,并且我有rb-readline(0.4.2)(人们推荐的最少
我的最终目标是安装当前版本的RubyonRails。我在OSXMountainLion上运行。到目前为止,这是我的过程:已安装的RVM$\curl-Lhttps://get.rvm.io|bash-sstable检查已知(我假设已批准)安装$rvmlistknown我看到当前的稳定版本可用[ruby-]2.0.0[-p247]输入命令安装$rvminstall2.0.0-p247注意:我也试过这些安装命令$rvminstallruby-2.0.0-p247$rvminstallruby=2.0.0-p247我很快就无处可去了。结果:$rvminstall2.0.0-p247Search
由于fast-stemmer的问题,我很难安装我想要的任何rubygem。我把我得到的错误放在下面。Buildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingfast-stemmer:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcreatingMakefilemake"DESTDIR="cleanmake"DESTDIR=
这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下
ruby如何管理内存。例如:如果我们在执行过程中采用C程序,则以下是内存模型。类似于这个ruby如何处理内存。C:__________________|||stack|||------------------||||------------------|||||Heap|||||__________________|||data|__________________|text|__________________Ruby:? 最佳答案 Ruby中没有“内存”这样的东西。Class#allocate分配一个对象并返回该对象。这就是程序
当我尝试安装Ruby时遇到此错误。我试过查看this和this但无济于事➜~brewinstallrubyWarning:YouareusingOSX10.12.Wedonotprovidesupportforthispre-releaseversion.Youmayencounterbuildfailuresorotherbreakages.Pleasecreatepull-requestsinsteadoffilingissues.==>Installingdependenciesforruby:readline,libyaml,makedepend==>Installingrub