<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Random on Nekonull's Garden</title><link>https://nekonull.me/tags/random/</link><description>Recent content in Random on Nekonull's Garden</description><generator>Hugo</generator><language>zh-CN</language><copyright>CC-BY-SA-4.0</copyright><lastBuildDate>Sun, 10 Sep 2023 16:05:00 +0800</lastBuildDate><atom:link href="https://nekonull.me/tags/random/index.xml" rel="self" type="application/rss+xml"/><item><title>随机分享（230910）：Typescript 中 Any 关闭类型检查 &amp; Linux 中的内存占用</title><link>https://nekonull.me/share/random-20230910/</link><pubDate>Sun, 10 Sep 2023 16:05:00 +0800</pubDate><guid>https://nekonull.me/share/random-20230910/</guid><description>&lt;p&gt;（没有干货，全是湿货&amp;hellip;不过至少写一些总比完全没有写强？）&lt;/p&gt;
&lt;h2 id="本周遇到的-bug"&gt;本周遇到的 Bug&lt;a class="td-heading-self-link" href="#%e6%9c%ac%e5%91%a8%e9%81%87%e5%88%b0%e7%9a%84-bug" aria-label="标题锚点"&gt;&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;遇到了两个前端相关的 bug，排查了很久，不过最后发现都是人的问题而非代码的问题&amp;hellip;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;CI 坏了还能跑？
&lt;ul&gt;
&lt;li&gt;现象：某前端项目，其他人参加开发的时候发现 master 分支无法 &lt;code&gt;npm install&lt;/code&gt;，但之前这个 repo 一直在正常更新版本，看 CI 日志也一切正常&lt;/li&gt;
&lt;li&gt;原因：发现问题是上游某依赖方对已发布的包重新发布，导致文件 hash 变化，&lt;code&gt;npm install&lt;/code&gt; 时实际文件 hash 和 lock 中 hash 不一致，所以失败；CI 之所以能跑是因为流水线里加了一层 cache，只要 &lt;code&gt;packages-lock.json&lt;/code&gt; 不变就会复用之前的 cache，而恰巧上游重发包之后这个文件一直没变过，所以每次跑 CI 都是拉的已有的 cache，没有实际在流水线里执行 &lt;code&gt;npm install&lt;/code&gt;，未能即使暴露故障&lt;/li&gt;
&lt;li&gt;解决：重建 &lt;code&gt;packages-lock.json&lt;/code&gt;，让 CI 中的 cache 无效&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;本地坏了，线上是好的？
&lt;ul&gt;
&lt;li&gt;现象：某前端项目，例行更新依赖库版本，发布前自测发现某功能测试环境不可用；但相同功能在线上一切正常&lt;/li&gt;
&lt;li&gt;原因：拉线上版本回本地排查，发现线上的版本和实际代码的主干版本不一致(!)；查阅发布记录，发现线上版本最近发布已经是一年多之前。和开发了解，原来现在的这个前端项目是原来的两个前端项目合并而来的，部署的时候其实要部署两次，但合并后的部署只部署了另一个模块，而没有部署当前模块，所以现在线上跑的实际上还是合并前的版本。&lt;/li&gt;
&lt;li&gt;解决：修复代码问题，本地验证通过后发布线上；补充 readme 说明发布时需要两个模块都发布&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="typescript-中-any-关闭了类型检查"&gt;Typescript 中 Any 关闭了类型检查&lt;a class="td-heading-self-link" href="#typescript-%e4%b8%ad-any-%e5%85%b3%e9%97%ad%e4%ba%86%e7%b1%bb%e5%9e%8b%e6%a3%80%e6%9f%a5" aria-label="标题锚点"&gt;&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;某后端项目，因为历史原因代码中有较多 any。最近发现代码中某处接受用户输入的位置有问题，默认值的类型不正确但依然通过了编译。示例如下：&lt;/p&gt;
&lt;div class="td-code td-code--untitled" id="td-code-0b2b7ae0-fence-0" data-td-code data-td-code-auto-id
data-td-language="typescript" data-td-line-count="3"&gt;
&lt;div class="td-code__viewport" id="td-code-0b2b7ae0-fence-0-viewport" data-td-code-viewport&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 不要这样用！
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;names&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="kr"&gt;as&lt;/span&gt; &lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;names&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// ^string[] ^any ^string
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;注意到这里 nullish coalescing （&lt;code&gt;??&lt;/code&gt;）的默认值是个 &lt;code&gt;string&lt;/code&gt; 而非 string[]。这段代码感觉上上不应该通过编译，但是因为 &lt;code&gt;(req.body as any)&lt;/code&gt; 的 &lt;code&gt;any&lt;/code&gt; 类型禁用了类型检查，因此编译时不会再检查缺省值，实际上可以编译通过。而如果不巧后续有函数需要使用 &lt;code&gt;string[]&lt;/code&gt; 才有的方法，而 &lt;code&gt;req.body&lt;/code&gt; 中的 &lt;code&gt;names&lt;/code&gt; 的确为 undefined，就会导致问题。&lt;/p&gt;
&lt;p&gt;要解决这个问题，需要提供了更强的类型提示，让 Typescript 的检查可以正常执行。&lt;/p&gt;
&lt;div class="td-code td-code--untitled" id="td-code-0b2b7ae0-fence-1" data-td-code data-td-code-auto-id
data-td-language="typescript" data-td-line-count="6"&gt;
&lt;div class="td-code__viewport" id="td-code-0b2b7ae0-fence-1-viewport" data-td-code-viewport&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 直接标记可能的类型：string[] 或 undefined
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;names&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="kr"&gt;as&lt;/span&gt; &lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;names&lt;/span&gt; &lt;span class="kr"&gt;as&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 通过一个自定义 type 来实现
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Nullable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;names&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="kr"&gt;as&lt;/span&gt; &lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;names&lt;/span&gt; &lt;span class="kr"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Nullable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;string&lt;/span&gt;&lt;span class="err"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://www.typescriptlang.org/play?#code/MYewdgzgLgBATgUwI4wLwwN4CgYwEYgAmAngFyYC&amp;#43;WFA3FlgPQMxggygC2ADgJYA2CGAjhwQcRs1CRYYAIYcEEctDg8wAcwDaAXTQwAFIiQA6AiRiyIFsMQCUxuQqsB&amp;#43;ZzADk7uk3bgIIAWM&amp;#43;EHV9R0VjACsQNX13ABp3W1s6CQtCQhgOMUFCBAAzNQQoHnAsKWgWeUVlKFUNHT1DZFMiYgsrWRt7cM6rFTUtXQAfGABXMDzCsARM1w8veh8xGEixyuBEWShBLpAoAAthGChiLgQsU-OYADkxvj5ZPAEAHgAVAD49N5hRiamiplRmB7nw6BUZNUIAAmWr1IZNIytcyWax2BxQjq3UFPV4DBraL7zTx0IA"&gt;Typescript Playground&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="linux-中的内存占用"&gt;Linux 中的内存占用&lt;a class="td-heading-self-link" href="#linux-%e4%b8%ad%e7%9a%84%e5%86%85%e5%ad%98%e5%8d%a0%e7%94%a8" aria-label="标题锚点"&gt;&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Linux 进程内存不同计算方法的区分：VSS, RSS, PSS, USS&lt;/p&gt;
&lt;div class="td-code td-code--untitled" id="td-code-0b2b7ae0-fence-2" data-td-code data-td-code-auto-id
data-td-language="" data-td-line-count="18"&gt;
&lt;div class="td-code__viewport" id="td-code-0b2b7ae0-fence-2-viewport" data-td-code-viewport&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;
┌────────┐
│ │
│ │ ┌────────┐
│ Unused │ │ │
│ (A) │ │ ... │◄───┐
│ │ │ │ │Other
│ │ ├────────┤ │Program&amp;#39;s
│ │ │ │ │Share
├────────┤ │ ... │◄───┘ (D)
│ │ │ │
│ Used │ ├────────┤
│ (B) │ │ │
│ │ │My Share│
│ │ │ (C) │
└────────┘ └────────┘
Exclusive Shared&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;可以把进程的内存占用视作上图。首先程序有自己独占的虚拟内存空间（Exclusive），其中可以分为已经使用了的（B）和属于自己但还未使用的（A）。其次进程还会使用一些共享内存（Shared），例如 so 动态运行库和 mmap 映射。考虑到这些共享内存多个进程都会用到，将其完全计算在某个特定进程名下听起来就不太合理，因此这里可以考虑类似于现实中的&amp;quot;公摊面积&amp;quot;，根据实际使用的进程数把这部分内存占用平摊成 N 份，当前进程只计算其中一份（C），剩余的计算在其他进程下（D）。&lt;/p&gt;
&lt;p&gt;由此我们可以得到四种不同的计算方法，见下表&lt;/p&gt;
&lt;div class="td-table-scroll td-table-scroll--static"&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th scope="col"&gt;指标&lt;/th&gt;
&lt;th scope="col"&gt;含义&lt;/th&gt;
&lt;th scope="col"&gt;组成&lt;/th&gt;
&lt;th scope="col"&gt;说明&lt;/th&gt;
&lt;th scope="col"&gt;图例&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;VSS&lt;/td&gt;
&lt;td&gt;虚拟内存集合（Virtual Set Size）&lt;/td&gt;
&lt;td&gt;所有进程地址空间中的所有内存&lt;/td&gt;
&lt;td&gt;进程可以访问的虚拟内存空间大小&lt;/td&gt;
&lt;td&gt;A+B+C+D&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RSS&lt;/td&gt;
&lt;td&gt;常驻内存集合（Resident Set Size）&lt;/td&gt;
&lt;td&gt;进程当前实际使用的物理内存&lt;/td&gt;
&lt;td&gt;实际分配的内存，不需要缺页中断就可以使用&lt;/td&gt;
&lt;td&gt;B+C+D&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PSS&lt;/td&gt;
&lt;td&gt;共享内存集合（Proportional Set Size）&lt;/td&gt;
&lt;td&gt;进程当前实际使用的物理内存，按比例分配共享内存&lt;/td&gt;
&lt;td&gt;按比例分配共享内存，适用于多个进程共享同一块内存的情况&lt;/td&gt;
&lt;td&gt;B+C&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;USS&lt;/td&gt;
&lt;td&gt;独立内存集合（Unique Set Size）&lt;/td&gt;
&lt;td&gt;进程独占使用的物理内存&lt;/td&gt;
&lt;td&gt;只包含进程独占使用的物理内存，不包括共享库和映射的文件&lt;/td&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;Via：&lt;a href="https://www.bilibili.com/video/BV11z4y1L7Xx"&gt;B站视频：用什么指标来衡量我的程序占用了多少内存&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="其他"&gt;其他&lt;a class="td-heading-self-link" href="#%e5%85%b6%e4%bb%96" aria-label="标题锚点"&gt;&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;最后顺带一提，本博客目前把 RSS 改为了全文输出模式（参考&lt;a href="https://www.godo.dev/tutorials/hugo-full-text-rss/"&gt;这篇文章&lt;/a&gt;，&lt;a href="https://github.com/jerrylususu/jerrylususu.github.io/commit/89e1c23d0b350baac0378ad735127cf17fb66c4b"&gt;实际 commit&lt;/a&gt;），希望可以帮到在 RSS 阅读器中阅读本博客的读者。&lt;/p&gt;</description></item></channel></rss>