ITADN
symphorien/nix-du
README.md
以下内容由 AI 翻译,如有问题请点此提交 issue 反馈

nix-du

nix-du 是一个旨在帮助回答以下问题的工具:

我应该从我的 nix store 中移除哪些 gc-roots 以释放一些空间? 我应该从我的 profile 中移除哪些包以释放一些空间?

入门

安装

nix-du 可在 nixpkgs >= 18.09-pre 中获取,请参阅下方的徽章。

Packaging status

在这种情况下,安装过程很简单。

nix-env -f <nixpkgs> -iA nix-du

有关其他安装方法,请参阅 INSTALL.md

运行

nix-du 将其分析结果以 DOT 格式输出为有向图(稍后会有更多介绍)。 因此,您需要安装 dot(通常以包名 graphviz 提供)。 然后,您可以将该图转换为各种更“传统”的图像格式。

例如:

# to svg
nix-du -s=500MB | dot -Tsvg > store.svg
# to png
nix-du -s=500MB | dot -Tpng > store.png

另一个选项是使用交互式查看器,例如 zgrviewer

nix-du -s=500MB > store.dot
zgrviewer -f store.dot

解读结果

哪些 gc-roots 占用了空间?

作为一个示例,想象以下场景。 您从一个全新的、空的 nix 安装开始。您安装 nix-index。然后您运行 nix-du

nix-du | dot -Tsvg > result.svg

左侧是 gc-roots。其他节点标注了包名, 但这几乎没有意义。重要的是它们的大小。蓝色表示“最轻”; 红色表示“最重”。从 A 到 B 的边意味着“只要 A 还活着, 你就无法移除 B”。如果你移除一个节点的所有入边,当你运行 nix-collect-garbage 时它_应该_ 消失,并且这_应该_释放大约 显示的空间量。

在此实例中,我们看到 rootcoucou 共享同一个 channel,其 重量约为 50Mo。从 channel 指向 user-environment 的箭头象征着,如果你想摆脱这 50 MB,你必须删除 rootcoucou 的 channel。

另一方面,nix-index 不出现在图中:如果你移除你的(唯一的) profile(黄色),那么 nix-index 就会消失。因此节点 nix-index 已经 与 profile 的节点合并。总之,如果你移除你的 profile,你将 节省大约 27 MB。

现在,你安装 graphviz

如果你删除第二个配置文件,你可以节省 graphviz 及其依赖项(140 MB) 但如果你删除第一个配置文件,你不会节省任何空间:nix-index 是两个配置文件的依赖项, 因此它现在拥有自己的节点。

如果你使用 nix-env -e graphviz 删除 graphviz

... 你意识到它仍然在你的第二个配置文件中。 所以如果你想节省空间,删除红色节点 :)

过滤器

在现实中,一个存储的依赖图往往非常大(并且 dot 会 在计算其布局时遇到困难),因此你可以要求 nix-du 对其进行简化:

  • 仅保留权重至少为 500 MB 的节点(即我只对节省至少 500 MB 感兴趣):
nix-du -s=500MB | dot -Tsvg > store.svg
  • 仅保留 50 个最重的内部节点
nix-du -n=50 | dot -Tsvg > store.svg

请注意,使用这些选项时:

  • 即使某些根节点不够重,它们也会被保留。
  • 节点的大小变为近似值,因此如果删除一个 500 MB 的根节点只节省了 450 MB, 请不要感到惊讶。

我的配置文件中的哪个元素占用了空间?

nix-du 也可以用于分析存储 路径的哪些依赖项导致了磁盘占用。为此,请传递 --root /nix/store/hash-foo。特别是,以下是一些有用的用例:

  • /etc/nixos/configuration.nix 中使用 environment.systemPackages 安装的哪些包占用的空间最多?(忽略所有小于 500 MB 的内容)
nix-du --root /run/current-system/sw/ -s 500MB > result.dot
  • 使用 nix-env 安装的哪些包占用的空间最多?
nix-du --root ~/.nix-profile > result.dot
限制

请注意,nix-du 主要关注根节点的直接依赖项;如果你希望传递依赖项清晰可见,请查看 nix-tree

示例

八边形框是根存储路径的子项(此处为我的 配置文件中的元素)。

例如,你可以看到 nix 在图中没有依赖项:它很可能是 从与配置文件其余部分不同的 nixpkgs 提交安装的,因此不 与它们共享依赖项。让我们解决这种情况:

nix-env -f "<nixpkgs>" -iA nix

现在,nix 的占用更小(因为它与我的配置中的其他部分共享依赖项), 并且你可以看到,如果不考虑它对 nix 的依赖,nix-du 仅占用几兆字节。

注意事项

--root 与外部引用者

请注意,当传入 --root 时,nix-du 将忽略指定 store 路径的传递闭包之外的所有内容。这可能导致意外的行为。 示例:如果你有如下 NixOS 配置:

{ pkgs, config, ... }:
{
  services.openssh.enable = true;
  environment.systemPackages = with pkgs; [ openssh ];
}

然后你运行

nix-du --root /run/current-system/sw/ > result.dot

并看到 openssh 占用了 123 MB 的空间。然后你从 你的 systemPackages 中移除 openssh,删除旧版本,但并未释放 123 MB。这是因为 其他某些内容(此处为单元文件 sshd.service)也依赖于 openssh, 从而阻止其删除,但被 nix-du 完全忽略了。

Store 优化

如果你使用了 store 优化(参见 nix-store --optimise 的文档),那么 不相关的 store 路径中的相同文件会被去重,并替换为硬链接 以节省空间。为了报告准确的大小,nix-du 需要扫描你的整个 store 以查找去重后的文件,这需要相当长的时间(尤其是在旋转硬盘上)。 (顺便说一句,这也是 nix-collect-garbage 耗时如此之长的原因)。

因此,默认情况下,nix-du 仅会在 活动路径中查找去重后的文件(选项 -O1)。你可以使用 -O2 获取完全精确的报告,或者使用 -O0 选择禁用去重文件检测。在后一种情况下,如果去重后的 文件出现在两个 store 路径中,它将被计算两次,并且大小将被 高估。

FAQ

这个图 究竟 是什么?

如果你既不使用 -s 也不使用 -n,那么输出图是根据你存储的参考图按如下方式派生的

  • 节点集是原始节点集在关系“这两个节点被(递归地)同一组 gc-roots 引用”下的商集
  • 如果两个类之间不是自环,并且在原始图中这两个类的任意元素之间存在边,则这两个类之间存在一条边

类的代表继承该类的总大小和一个任意成员的名称。大小是最重要的 信息。节点的名称有时有用,但通常也无意义。例如,我已经看到一个巨大的节点 glibc-localestexlive 组件之间存在一条边,这令人惊讶,因为 glibc-locales 没有任何引用...

如果你使用 -s(仅保留大于给定大小的节点)或 -n(仅保留最大的 n 个节点)中的任何一个,则会进行近似 处理,因此结果可能不太准确(但可读性要好得多!)

nix-du 是否取代了 nix-collect-garbage

不,nix-du 只是一个诊断工具,它不会修改任何内容。

我的存储比图的总大小还要大

仅显示活动路径。或者参见关于优化的部分。

我的存储比显示的轻得多!

这可能与存储优化有关。参见相关部分。 或者如果你使用 --root,则仅显示根的传递闭包。

我删除了一个巨大的节点,但 nix-collect-garbage 只释放了很少的空间!

如果没有 --root,这可能与优化有关。请参阅相关章节。 如果有 --root,可能发生的情况是,你删除的节点在根节点的传递闭包之外有一个引用者。请参阅上方关于 --root 的章节中的示例。

我使用 -n 60 请求了 60 个节点,但我得到了 120 个!

当你使用 -n-s 应用过滤器时,所有具有被过滤器保留的(传递)子节点的根节点也会被保留。 剩余的根节点会被合并到 {filtered out} 节点中。

什么是 {transient} 节点?

这是一个合并所有内存和临时根节点的节点,用 nix 的术语来说。 内存根节点代表一个通过 mmap 映射了存储路径的进程,而临时根节点 是由 nix 构建机制为当前正在运行的构建的依赖项创建的根节点。 简而言之:此节点表示依赖于存储但会在重启后消失的活跃内容。