4作者: pixelworm7 个月前
我喜欢看旧平台或软件的 UI。那种像素化的外观比现代 UI 更吸引我。<p>对我来说,我最喜欢的是 PalmPilot 早期的一些 UI。对于一个只有 160×160 像素的显示屏来说,它们出人意料地好。它们今天看起来可能不是最好看的,但它们非常实用。在某些方面,我实际上更喜欢旧的 UI 设计。现代 UI 组件感觉更复杂,而且在我看来,会导致更多错误。<p>大家最喜欢的 UI 是什么,旧的还是现代的?
3作者: hilti7 个月前
我一直在构建一个跨平台的 JSONL 查看器应用程序,用于处理多 GB 的文件。它在 macOS(我的开发机器)上完美运行,但在 Windows 上总是崩溃,崩溃点恰好是 2,650 KB。以下是调试过程以及那个带来巨大差异的微小修复。<p>问题所在<p>- macOS:轻松处理 5GB+ 文件 - Windows:每次都在 2,650 KB 时崩溃 - 相同的代码库,使用 MinGW 从 Mac Silicon 交叉编译到 Windows<p>调查过程<p>添加了详细的日志记录来跟踪执行过程。崩溃发生在字符串驻留期间,在成功解析了大约 6,000 行之后。不是在解析期间,也不是在文件 I/O 期间,而是在合并阶段。<p>根本原因<p>我的 StringPool 类使用 std::unordered_map&lt;std::string_view, uint32_t&gt; 来去重字符串。string_view 指向一个 std::vector&lt;std::string&gt;。<p>当 vector 增长并重新分配时,所有 string_view 键都变成了悬空指针。哈希映射中充满了无效的引用。<p>为什么它在 macOS 上有效?不同的内存分配器行为,不同的默认堆栈大小(8MB vs 1MB),不同的重新分配模式。<p>修复方法<p>之前(出错):<p><pre><code> uint32_t intern(std::string_view str) { auto it = indices_.find(str); if (it != indices_.end()) return it-&gt;second; uint32_t idx = strings_.size(); strings_.push_back(std::string(str)); indices_[std::string_view(strings_.back())] = idx; &#x2F;&#x2F; 危险! return idx; } </code></pre> 之后(已修复):<p><pre><code> uint32_t intern(const std::string&amp; str) { auto it = indices_.find(std::string_view(str)); if (it != indices_.end()) return it-&gt;second; &#x2F;&#x2F; 如果我们即将重新分配,则预先重建 if (strings_.size() &gt;= strings_.capacity()) { strings_.reserve(strings_.capacity() * 2); rebuildIndices(); &#x2F;&#x2F; 修复所有 string_view! } uint32_t idx = strings_.size(); strings_.push_back(str); indices_[std::string_view(strings_.back())] = idx; return idx; } void rebuildIndices() { indices_.clear(); for (size_t i = 0; i &lt; strings_.size(); i++) { indices_[std::string_view(strings_[i])] = i; } } </code></pre> 结果<p>- 100 万行:Windows 上 6 秒 - 多 GB 文件:无崩溃 - 约 166,000 行/秒的吞吐量 - 跨平台稳定性<p>经验教训<p>1. std::string_view 强大但危险 - 它是一个非拥有的引用。当底层存储移动时,你持有的就是垃圾。<p>2. 跨平台测试至关重要 - 由于不同的分配器行为和更大的默认堆栈大小,该错误在 macOS 上是不可见的。<p>3. 对于交叉编译,结构化日志记录胜过调试器 - 我正在从 Mac 交叉编译到 Windows。将带时间戳的日志记录添加到文件中,可以立即明确崩溃点。<p>4. 小改动,巨大影响 - 一个函数,大约 15 行代码,将“在 2MB 时崩溃”变成了“处理 5GB+ 文件”<p>5. 性能保持出色 - 重建只发生在 vector 重新分配期间(指数增长),因此分摊成本可以忽略不计。<p>技术栈<p>- simdjson (v4.2.2) 用于解析 - 多线程解析(我的测试机器上有 20 个线程) - 列式存储,用于内存效率 - C++17,使用 MinGW-w64 交叉编译<p>这是一个令人警醒的提醒,最关键的错误往往是最简单的,隐藏在平台差异的背后。<p>很乐意讨论实现细节、simdjson 的使用或跨平台 C++ 调试技术!