首页 文章 精选 留言 我的

精选列表

搜索[文本图像鉴伪],共10000篇文章
优秀的个人博客,低调大师

前车之鉴:聊聊钉钉 Flutter 落地桌面端踩过的“坑” | Dutter

作者:刘太举(驽良) 《Dutter 系列文章》将阐述钉钉基于 Flutter 构建的跨四端应用框架(代号 Dutter)的技术实践与踩坑经验,共分为上、下两篇,上篇内容可点击 Dutter | 钉钉 Flutter 跨四端方案设计与技术实践,本文为下篇,感谢阅读。 本文主要介绍一下钉钉 Flutter 业务灰度过程中,在桌面端遇到并处理过的几个 FlutterEngine 层面的 Bug。具体包含: Mac 端: FlutterEngine 退出之后内存泄漏问题; FlutterEngine shutdown 阶段死锁问题; 低版本 macOS OpenGL 析构阶段 Crash 问题; Windows 端: Win7 设备渲染模块「Crash + 残影」问题; FlutterPlugin 注册阶段野指针 Crash; Flutter Window 可见性变化之后页面白屏。 下面来为大家分别介绍一下。 FlutterEngine Mac 端问题 1.1 FlutterEngine 退出之后内存泄漏问题 问题背景 Mac 端 FlutterViewController 在销毁之后,其开辟的内存并未并实际释放,会出现内存泄漏问题。此问题在 Flutter issue 中有一些讨论,但一直未有明确定位。在钉钉 Mac 端 Flutter 业务灰度过程中也遇到此问题,如无法处理将直接影响 Dutter 在 Mac 端落地的可行性: 定位分析 一句话原因: Mac 端 FlutterEngine 实现中对 weak property 使用不合理导致。FlutterViewController 强持有 FlutterEngine,后者持有一个指向 FlutterViewController 的 weak property。FlutterViewController 在 dealloc 流程中尝试释放 FlutterEngine,但是此时 FlutterEngine 中持有的 weak property 已经无法正确访问(nil),导致释放流程未能正常执行,出现泄漏。 下面结合具体实现来为大家做一个简单说明。 由于设计到 OC 和 C++ 对象生命周期管理问题, FlutterEngine 内部对象持有关系略微特殊一些,大致如下图所示: FlutterViewController 作为对外暴露的主要 Class,负责创建并持有 FlutterEngine 以及 FlutterView; FluterEngine 在初始化阶段会自己强持有自己,并在 shutdown 时自我 Release; FlutterEngine 会创建并持有 FlutterRenderer,FlutterRenderer 会强持有 FlutterView; FlutterEngine 间接强持有 FlutterView; FlutterEngine 有一个指向 FlutterViewController 的弱引用指针。 正常情况下,FlutterViewController 退出之后,会通过调用 FlutterEngine 的 setViewController 传入 nil 的方式,来触发 FlutterEngine shudown 动作。参考实现如下: 即正常情况下,FlutterViewController dealloc 之后应该触发 369 行代码运行,进而释放 FlutterEngine 资源。但是实际运行情况缺不是这样,在代码运行到 359 行时,尝试判断 if (_viewController != controller) 时并未成立。通过上述代码我们知道,controller 是外部传入的对象此时为 nil;_viewController 作为一个 weak proptry,在 FlutterViewController 进入 dealloc 流程之后也变为 nil。因而在此流程下,我们希望中的 shutDownEngine 方法并未被调用。 处理方案 问题定位之后处理方式就很简单了,可以在 FlutterViewController dealloc 的时候手动触发 FlutterEngine shutDownEngine 方法。并且通过在上层通过 OC 动态特性 hook 实现、或者直接修改重新编译 FlutterEngine 都可以。 但此处修改一定要谨慎,注意完整还原 FlutterEngine 中的 shutdown 流程,否则可能导致我们遇到的第二个问题:死锁。 1.2 FlutterEngine shutdown 阶段死锁问题 问题背景 钉钉最初在处理上述「FlutterEngine 泄漏」问题时,采用了一种相对比较简单的方案:在 FlutterViewController dealloc 方法中,手动调用 FlutterEngine 提供的 shutDownEngine 方法,手动触发相关资源释放。 通过此方案,FlutterViewController 退出之后内存确实出现了下降,但是在灰度时发现偶尔会有整个页面卡死的情况。通过对出现问题的链路进行简单分析以及配合暴力测试,我们在 debug 环境对问题做了还原。最终初确认 UI 线程与 Raster 线程出现死锁,死锁之后的线程状态大致如下。 UI 线程状态: Raster 线程: 定位分析 一句话原因: 钉钉侧调用 FlutterEngine shutDownEngine 方法不合理导致。shutDownEngine 之前,必须先调用 FlutterView 的 shutdown 方法来停止渲染流程。待渲染流程正常停止之后,才可进入 FlutterEngine 资源释放流程,否则即有可能出现上述死锁问题。 因为此问题为钉钉调用不合理导致,具体异常原因不再深入分析,感兴趣的同学可以根据上述线索自行查阅。 处理方案 在上层补全 FlutterEngine 释放流程,在调用 FlutterEngine shutDownEngine 之前首先调用 FlutterView shutdown 停止 Raster 线程。 1.3 低版本 macOS OpenGL 析构阶段 Crash 问题 问题背景 此问题还是接两个问题,在处理完问题1和问题2之后,参考 FlutterEngine shutdown 流程,钉钉会在 FlutterViewController 析构之后做3件事情: 将 FlutterRenderer 中绑定的 FlutterView 置为 nil; 调用 FlutterView shutdown 方法; 调用 FlutterEngine shutDownEngine 方法。 经过一系列处理之后,测试发现内存泄漏和死锁问题基本得以根治。但是在内部灰度过程中发现低版本 macOS 上会出现 Crash,堆栈大致如下: 定位分析 一句话原因: 与问题2类似,此问题也是因为钉钉处理泄漏问题而引入。其大致由两方面因素迭代导致。一方面因为重置 FlutterOpenGLRenderer 绑定的 FlutterView,导致在 embedder 层创建的 OpenGL 对象被提前释放;另外一方面因为低版本 macOS OpenGL 实现不完善析构流程中未能对关键链路做保护,进而导致异常。 下面对异常相关代码做一下简答分析,避免其他同学再遇到类似问题。 1、在 FlutterEngine setViewController 方法中,如果处于释放流程,会调用 FlutterOpenGLRenderer setFlutterView 方法,并传入 nil: 2、FlutterOpenGLRenderer setFlutterView 方法在入参为 nil 时,会释放其内部维护的 NSOpenGLContext 对象: 3、FlutterEngine 底层实现会在 GrDirectContext 对象析构时执行 flush,如果此时 OpenGL 相关对象已经释放,在低版本 macOS(10.11, 10.12)会出现 Crash: 处理方案 由于出现问题的部分是由钉钉上层代码触发,处理相对比较简单。最终我们在所有使用 OpenGL 渲染的 Mac 设备上(macOS 10.14 之前的版本)移除 FlutterView 置空动作。即最终 FlutterViewController 释放阶段只执行以下两个动作: 调用 FlutterView shutdown 方法; 调用 FlutterEngine shutDownEngine 方法。 FlutterEngine Windows 端问题 2.1 Win7 设备渲染模块「Crash + 残影」问题 问题背景 此问题背景略微有些复杂,如果细分来看的话,此问题应该可以拆分为两个子问题。 第一个问题是,在部分 Win7 设备上(x86 + x64)出现 d3d11 导致的 Crash,堆栈大致如下: 由于迟迟无法定位导致此问题的具体原因、且 Flutter 官方表示他们对 Win7 设备的覆盖度并不完善「参考」。因此我们决定对 FlutterEngine 稍加定制,在 Win7 等陈旧设备上强制通过「软解模式」来渲染 Flutter 页面。 本以为通过此方式可以绕过此问题,但很不幸运的是此方案暴露了 FlutterEngine 里另外一个 Bug:通过「软解模式」来渲染页面时,FlutterViewController 关闭只有有一定概率会导致 Windows 桌面出现残影。 定位分析 一句话原因: 此问题主要是因为 FlutterEngine 内部 shutdown 流程中,未及时修改 FlutterWindowsEngine 指向 FlutterWindowsView 对象的指针,导致多线程场景下出现野指针;因为野指针导致raster 线程在 FlutterWindowsView 已经销毁情况下仍向其输出绘制帧,进而导致异常。 在定位时,我们通过增加辅助 log 的方式来加快问题定位过程。通过对关键节点补充日志,我们很快发现了可疑点: 上图是出现问题之后关键节点输出的日志。我们通过日志可以得到以下关键信息: OnBitmapSurfaceUpdated 是 FlutterWindowsView 的成员函数。但是在输出最后两行 OnBitmapSurfaceUpdated 方法时,FlutterWindowsView 的析构函数已被执行(野指针); 最后一次执行 OnBitmapSurfaceUpdated 时,渲染使用的 Window 句柄为 nullptr,即可供渲染的窗口(与 FlutterWindowsView 绑定)以被释放。 因为最后渲染所使用 Window 句柄为 nullptr,进而导致出现残影问题。 补充说明:在调用 C++ 成员函数时,即使调用时 this 已经为野指针,但只要成员函数中并未访问到 this 对象,则不会出现内存访问异常(Crash)。 处理方案 修改 FlutterEngine 内部实现,在 SoftwareRenderer 模式下 FlutterWindowsView 析构时,置空 FlutterWindowsEngine 指向其的指针(因 GPU 模式会有异常输出,暂未修改): 通过此方式,可以保证在 FlutterWindowsView 销毁之后 raster 线程中的任务不会再回调渲染接口: 2.2 FlutterPlugin 注册阶段野指针 Crash 问题背景 在钉钉 Flutter 版本「+面板」业务 Windows 端一灰、二灰阶段出现较多例 Crash,客户端整体 Crash 率高达 x%: 通过简单分析,还原 Crash 堆栈大致如下: 从堆栈可以达到两个比较重要的信息: Crash 出现在 FlutterEngine 初始化阶段,具体是在 Plugin 注册时出现异常; 导致 Crash 原因是野指针问题。 定位分析 一句话原因: Flutter 为 Windows 平台提供 wrapper 层代码中,包含一个设计上为单例的对象 PluginRegistrarManager。PluginRegistrarManager 主要服务于 FlutterPlugin 注册、设计上为一个单例,其内部通过 map 维持了一个 FlutterEngine 指针与 Registrar 的映射关系,保证 Registrar 与 FlutterEngine 生命周期保持一致。但是因为 wrapper 层的代码在构建时被编入了 pulgin.dll,导致每一个 plugin.dll 中都包含一份 PluginRegistrarManager 实现副本,即「单例机制」失效。带来的问题是 FlutterEngine 析构时无法正确清除 PluginRegistrarManager 中的绑定关系,导致其内部维护一个失效的指针地址,再次访问时出现 Crash。 下面简单介绍一下分析过程。通过暴力测试,我们可以复现问题: 根据上图可以确认,出现 Crash 是因为 FlutterEngine 对象野指针导致。进一步定位插件注册时 Engine 指针来源,最终可定位到 flutter::PluginRegistrarManager::GetInstance()->GetRegistrar() 方法中: 进一步分析 PluginRegistrarManager 中的实现,可知 GetRegistrar 内部需要 map + emplace 方法来维系 FlutterEngine 地址与 Registrar 关系: 其内部会通过 FlutterDesktopPluginRegistrarSetDestructionHandler 将方法注册到底层 Engine 对象中,其会在 FlutterEngine 析构时被调用,进而解除绑定关系: 问题即出现在此流程中,如果 PluginRegistrarManager 并非真正的单例,且 FlutterEngine 只能维护一份有效的 OnRegistrarDestroyed 回调,那么在 FlutterEngine 析构时,有部分 PluginRegistrarManager 对象中保存的 FlutterEngine 地址不会被清除,再次使用时即会导致问题。 处理方案 修改 FlutterEngine wrapper 层 PluginRegistrarManager 实现,优化「单例」实现方案。将单例生命周期周期管理下层到底层,wrapper 层仅负责提供相关服务。 具体可参考: 2.3 Flutter Window 可见性变化之后页面白屏 问题背景 在 Windows 端 Flutter 页面中,如果将 Flutter Window: 先通过 ShowWindow(flutter_wnd, SW_HIDE) 隐藏; 再通过 ShowWindow(flutter_wnd, SW_SHOWNORMAL) 显示出来。 会发现 Flutter 页面内容无法正常展示,画布上为空白一片。如果在白屏之后通过 setState 或者 拖拽窗口等方式触发 Flutter 页面刷新,则内容可被正常渲染。 定位分析 此问题相对比较明确,Flutter Windows 端实现存在 bug,在 Window 可见性发生变化之后,应重新出发 flush 将最新视图绘制到对应窗口,但是目前此流程并未实现,导致出现以上问题。 处理方案 此问题已经提交issue,暂时钉钉侧是通过上层补偿的方式来绕过此此问题。我们在 Native Window 可视性变化之后,手动通知 Flutter 侧刷新当前可见页面,以此触发重绘、规避问题。 总结 以上即为钉钉 Flutter 落地过程中桌面端处理的几大主要问题。从我们实际体验来看,虽然在 Flutter v2.10 版本已经正式发布对 Windows 的支持。但仅从稳定性角度来看,Flutter 在 Mac 端的表现无疑要优于 WIndows。如果有其它团队希望在使用 Flutter 在桌面单端做一下尝试,我们优先推荐选择 Mac 端,其无论是上手门槛还是性能稳定性表现,相比 Windows 端要更有优势。 关注【阿里巴巴移动技术】,阿里前沿移动干货&实践给你思考!

优秀的个人博客,低调大师

被呼吁抵制,7-Zip 伪开源还留有后门?网友:无稽之谈

一位名为 Paul 的作者发布了一篇呼吁抵制知名压缩软件 7-Zip 的文章。7-Zip 是一个由俄罗斯开发者 Igor Pavlov 开发,发布于 1999 年的老牌软件,其源码托管在 Sourceforge;大部分的源码都适用于 GNU LGPL 许可,unRAR 代码则采用的是 GNU LGPL + unRAR 限制的混合许可证。 Paul 首先抨击7-Zip 的点在于,他认为该软件是“有限的”开源。原因则在于:7-Zip 的代码没有托管在 Github、Gitlab 或任何一个公共代码托管平台上,只有一个 Sourceforge 官方页面上的 src.7z。“没有历史、没有 committer、没有名字、也没有文档,只有一个存档”。 他还引用了一个 2010 年的讨论帖来指出,从源码构建 7-Zip 存在很大难度。“如果你需要自己编译 7-zip - 一些 tweaks是不可避免的。那么为什么需要 tweaks而没有 commit history 呢?只是因为作者不想让你从源代码中构建应用程序,而且有些部分可能没有包括在内,或者包含了一些 'special' bugs。有了 commit history,可以更轻松地跟踪任何更改并还原任何错误的部分;也更容易运送一些见不得光的元素,如隐藏的遥测或后门。” 且 Paul 认为,Sourceforge 的声誉并不好;因为该平台曾被指控在 Windows .exe 文件和自解压文件中包含间谍软件和恶意软件。此外,该作者还列举了一些 7-Zip 存在的安全漏洞。最后,他抵制 7-Zip 还有一个关键原因是俄乌冲突:“最好不要使用俄罗斯的软件,不仅仅是出于对乌克兰的声援,该软件还可能增加高级安全风险。” 文章指出了 7-Zip 的一些替代方案,其中包括 Nanazip(7-Zip 分支)和基于 FreePascal 的PeaZip 等。 这一抵制博文不可避免的在 Reddit 上引起了热议,但就当下情况来看,还是与 Paul 持相反意见的人居多。其中一位名为qvop的网友就针对博客中的内容逐一进行了反驳。 首先,7-Zip 就是开源的(忽略 unRAR 许可部分),没有任何一项规定指出开源软件的源码必须托管在某个特定平台;有问题的是 Paul 自身。 其次,事实上是存在一些(公认的相对稀少的)文件,内容包括更新日志以及关于如何编译程序和它的一些内部工作的描述。而一些其余的内容也并不在开源发布的要求规范内,且如果开发者是单独开发而不寻求贡献的话,其作用也不大。 关于后门之类的指控,则更像是接近阴谋论的范畴了。没有任何实际证据表明开发者有意加大编译难度,或者故意包含"special bugs"。相反,开发团队在开发和维护这个软件方面有超过 20 年的记录,他们显然没有过文章作者所暗示的种种意图或行为;在不同环境下编译软件的问题是完全正常的。同理,难道开发人员现在还在与 Sourceforge 合作在提供的二进制文件中隐藏恶意软件?这一指控同样也没有实际证据。 最后关于站队。因为开发者的国籍而抵制开源软件是一个愚蠢的举措,尤其在开发团队并没有表明立场的情况下。“我不确定开发人员被迫在 7zip 中包含恶意代码的实际风险有多大,但我认为如果普京想要渗透开源软件,会有很多更简单、更隐蔽的方法。” “总而言之,这在我看来是一个无稽之谈,掺杂着一些权利和阴谋论。” 网友JonnyRocks: 总结:发帖人不喜欢 7-zip 创建者的名字,想 fork 它,结果被搞糊涂了。 网友bemenaker: nanazip 是 7zip 的一个分支。它也有 7zip 所缺少的 win11 集成。 我不是在为这篇博文辩护,只是想说那个作者是个白痴。 网友boom_bap_bnc: 我会继续使用它,谢谢。 网友atoponce则感叹道“奇奇怪怪”: 并非所有的开源软件都有公开的源代码库和 commit 历史。安全问题当然令人担忧,但在 SourceForge 上托管源代码和二进制文件是完全可以的。文章中引用的恶意软件争议在 7 年前就已经结束了。 最后,因为开源软件的总部在俄罗斯而抵制它是很奇怪的,更何况 7-Zip 的作者也并没有因为你使用该软件而赚到钱。

优秀的个人博客,低调大师

以假乱真,大学生用 GPT-3 生成伪文章成功骗过众人

为了证实 GPT-3 对人们写作和阅读方式可能带来的影响,前不久,来自加州大学伯克利分校的学生Liam Porr 做了一项实验。 他以Adolos 为笔名开通博客,在其中发布由GPT-3 模型生成的文章,第一篇就被顶至 Hacker News 头条,还被 medium 等各大平台转载,该博客迅速获得了 60 位关注者及大约 2.6 万访问量。但注意到文章是由人工智能生成,且提出质疑的人屈指可数。 这篇题为《觉得生产力低下?也许你应该停止过度思考》的文章,引来一众网友共情并应声附和。其中一位评论者指出“这可能是 GPT-3 编写的,实质内容含量为零”,却遭致他人反驳,被要求提供理由,以及“保持文明,不要侮辱他人”。 实际上,Porr 本人仅指定了标题和简介,其他内容都交由GPT-3 完成。他发现,GPT-3 不擅长逻辑和理性,但能够创造漂亮的语句。这样的文章经不起仔细推敲,可并不妨碍仍有大量人喜爱阅读它们,往往只要抛出一个受欢迎的话题就足够。 GPT-3 被认为是迄今为止最大的 AI 语言模型,由 1750 亿个参数组成。这是一个史无前例的庞大语言模型,几乎所有可以用文字表达的工作它都能胜任,可以指导它回答问题、写文章、写诗歌、甚至写代码。 其背后的开发者OpenAI 目前仅开放了少量 GPT-3 的 API 测试资格,Porr 通过伯克利 AI 社区找到了一位具有资格的博士生进行合作。从产生这个想法,到利用GPT-3 生成具有病毒式传播潜力的文章,Porr 仅用了短短几个小时。而在此之前的一周内,他还不了解GPT-3 为何物。 实验持续了两个星期,最终结束于Adolos博客发布的最后一篇文章《若我没有道德,会拿 GPT-3 来做什么》,文章指出“滥用这项技术的方法比制造纳粹宣传还要微妙得多”。当然,这篇文章由GPT-3 生成还是由人类撰写也是一个谜。 Porr 本人最后也在自己的博客中解释了整个实验过程,除了对当前网络内容质量和人们分辨能力的警醒,他还提出了GPT-3 这类技术对媒体机构可能产生的影响。他认为,即便能够大幅降低人力成本,传统的老牌媒体仍然会因专业性对其感到抵触,而新媒体也许会从中获得施展空间。 关于 GPT-3,也可阅读:人类算力天花板?1750 亿参数的 AI 模型 GPT-3 引爆硅谷

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册