到目前为止,我已经能够将 Apple 的虚拟内存交换文件移动到硬盘上的专用分区。我使用的技术在线在 forums.macosxhints.com 上。
然而,随着 Snow Leopard 开发者预览版的推出,这种方法不再有效。有人知道在新操作系统中如何实现吗?
更新:我已经标记dblu 的回答尽管它没有完全发挥作用,但我还是接受了,因为他给出了非常详细的说明,而且他的使用建议plutil
最终为我指明了正确的方向。完整的、可行的解决方案发布在问题中,因为我没有足够的声誉来编辑已接受的答案。
更新 #2:更改了流程以进行说明ekl 的技术,通过消除中间 shell 脚本的需要,大大简化了整个过程:
完整解决方案:
1.
打开终端并备份 Apple 默认的 dynamic_pager.plist:
$ cd /System/Library/LaunchDaemons
$ sudo cp com.apple.dynamic_pager.plist{,_bak}
2.
将 plist 从二进制转换为纯 XML:
$ sudo plutil -convert xml1 com.apple.dynamic_pager.plist
3.
使用您选择的文本编辑器打开转换后的 plist。(我使用pico
,有关使用的示例,请参阅 dblu 的答案vim
):
$ sudo pico -w com.apple.dynamic_pager.plist
它应该如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs$
<plist version="1.0">
<dict>
<key>EnableTransactions</key>
<true/>
<key>HopefullyExitsLast</key>
<true/>
<key>Label</key>
<string>com.apple.dynamic_pager</string>
<key>OnDemand</key>
<false/>
<key>ProgramArguments</key>
<array>
<string>/sbin/dynamic_pager</string>
<string>-F</string>
<string>/private/var/vm/swapfile</string>
</array>
</dict>
</plist>
4.
修改 ProgramArguments 数组(第 13 行至第 18 行)以使用 wait4path shell 命令(如齐尔),然后再启动 dynamic_pager。有关为什么需要这样做的详细信息,请参阅注释 #1。在下面的示例中,我的分区称为“Swap”,我选择将交换文件放在该分区上的隐藏目录中,称为“.vm”确保您指定的目录确实存在。XML 应如下所示:
<key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>-c</string>
<string>/bin/wait4path /Volumes/Swap/ &&
/sbin/dynamic_pager -F /Volumes/Swap/.vm/swapfile</string>
</array>
5.
保存 plist,然后返回到终端提示符。使用pico
,命令将是:
<ctrl+o> to save the file
<enter> to accept the same filename (com.apple.dynamic_pager.plist)
<ctrl+x> to exit
6.
将修改后的 plist 转换回二进制:
$ sudo plutil -convert binary1 com.apple.dynamic_pager.plist
7.
重启 Mac。如果遇到问题,请在启动提示音后立即按住 Command-v 切换到详细启动模式。这样您就可以看到启动过程中出现的所有启动消息。如果遇到更严重的问题(即您从未看到登录屏幕),请改为按住 Command-s。这将以单用户模式启动计算机(没有图形用户界面,只有命令提示符),并允许您恢复在步骤 1 中创建的 com.apple.dynamic_pager.plist 的备份副本。
8.
计算机启动后,启动终端并验证交换文件是否已实际移动:
$ cd /Volumes/Swap/.vm
$ ls -l
你应该看到类似这样的内容:
-rw------- 1 someUser staff 67108864 18 Sep 12:02 swapfile0
9.
删除旧的交换文件:
$ cd /private/var/vm
$ sudo rm swapfile*
10.
利润!
注 1
不使用的情况下修改 plist 中 dynamic_pager 的参数wait4path
并不总是有效,并且当它失败时,它会以一种惊人的静默方式失败。问题源于 dynamic_pager 在启动过程的很早的时候就启动了。如果在首次加载 dynamic_pager 时尚未挂载交换分区(根据我的经验,99% 的时间都会发生这种情况),则系统将伪造其路径。它将在您的 /Volumes 目录中创建一个符号链接,该链接与您的交换分区同名,但指向默认交换文件位置(/private/var/vm)。然后,当您的实际交换分区挂载时,它将被赋予名称Swap 1
(或YourDriveName 1
)。您可以通过打开终端并列出 /Volumes 目录的内容来查看问题:
$ cd /Volumes
$ ls -l
你会看到类似这样的内容:
drwxrwxrwx 11 yourUser staff 442 16 Sep 12:13 Swap -> private/var/vm
drwxrwxrwx 14 yourUser staff 5 16 Sep 12:13 Swap 1
lrwxr-xr-x 1 root admin 1 17 Sep 12:01 System -> /
请注意,此故障可能非常很难发现。如果你按照我在第 12 步中展示的那样检查交换文件,你仍然会看到它们! 符号链接会让您的交换文件看起来好像已被移动,尽管它们实际上存储在默认位置。
笔记2
我最初无法在 Snow Leopard 中实现此功能,因为 com.apple.dynamic_pager.plist 是以二进制格式存储的。我复制了原始文件,并使用 Apple 的 Property List Editor(Xcode 中提供)打开它以进行更改,但此过程向 plist 文件添加了一些扩展属性,导致系统忽略它并仅使用默认值。正如 dblu 指出的那样,使用 将plutil
文件转换为纯 XML 非常有效。
注 3
您可以检查控制台应用程序以查看 dynamic_pager_init 回显到屏幕上的任何消息。如果您看到以下几行反复出现,则说明设置存在问题。我遇到这些消息是因为我忘记创建我在 dynamic_pager_init 中指定的“.vm”目录。
com.apple.launchd[1] (com.apple.dynamic_pager[176]) Exited with exit code: 1
com.apple.launchd[1] (com.apple.dynamic_pager) Throttling respawn: Will start in 10 seconds
当一切正常时,您可能只会看到上述消息几次,然后就不再出现“节流重生”消息。这意味着系统确实必须等待分区加载,但最终成功了。
答案1
笔记:另请参阅问题本身中已更正/改进的答案。
以下解决方案对我有用:
打开一个终端并备份您将在稍后更改的 com.apple.dynamic_pager.plist:
$ cd /系统/库/LaunchDaemons $ sudo cp com.apple.dynamic_pager.plist{,_bak}
将二进制 plist 转换为 xml:
$ sudo plutil -convert xml1 com.apple.dynamic_pager.plist
并使用您喜欢的文本编辑器打开它
$ sudo vim com.apple.dynamic_pager.plist
它看起来是这样的:
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3 <plist version="1.0">
4 <dict>
5 <key>EnableTransactions</key>
6 <true/>
7 <key>HopefullyExitsLast</key>
8 <true/>
9 <key>Label</key>
10 <string>com.apple.dynamic_pager</string>
11 <key>OnDemand</key>
12 <false/>
13 <key>ProgramArguments</key>
14 <array>
15 <string>/sbin/dynamic_pager</string>
16 <string>-F</string>
17 <string>/private/var/vm/swapfile</string>
18 </array>
19 </dict>
20 </plist>
在第 17 行修改 /private/var/vm/swapfile(例如 /Volumes/partition2/swapfile),保存并关闭编辑器(“:x”将在 vim 中执行这两项操作)。
将 plist 文件转换回二进制:
$ sudo plutil -convert binary1 com.apple.dynamic_pager.plist
重新启动 Mac 后,您应该会在指定的目录中找到交换文件。
如果遇到任何问题,可以使用以下命令恢复在第一步中创建的备份:
$ cd /系统/库/LaunchDaemons $ sudo cp com.apple.dynamic_pager.plist{_bak,}
答案2
我采纳了这个想法,并通过解决增长和回收策略进一步推进了它。
详情请见http://www.crypticide.com/dropsafe/article/3848;我想发布指向“dynamicpagerwrapper”GoogleCode 项目页面的链接,但博客告诉我我没有足够的声誉点数……
答案3
只是一个问题:为什么不直接编辑 .plist 文件添加wait4path
,而是使用中间的dynamic_pager_init
?
像这样:
编辑:正如 e.James 的评论和我下面的评论所解释的那样,紧接着的 XML 块并不好,因为有一个错误(缺少 &&),而且只有数组的第一个参数 ProgramArguments
它被解析为要运行的程序!
但..(向下滚动)
...
13 <key>ProgramArguments</key>
14 <array>
15 <string>/bin/wait4path</string>
16 <string>/Volumes/Swap/</string>
17 <string>/sbin/dynamic_pager</string>
18 <string>-F</string>
19 <string>/Volumes/Swap/.vm/swapfile</string>
20 </array>
...
错误的 xml 块结尾
此 XML 块应该代替工作:
...
13 <key>ProgramArguments</key>
14 <array>
15 <string>/bin/bash</string>
16 <string>-c</string>
17 <string>/bin/wait4path /Volumes/Swap/ && /sbin/dynamic_pager -F /Volumes/Swap/.vm/swapfile</string>
18 </array>
...
请记住,我仍然没有足够的时间来安全地尝试此设置,但我尝试运行以相同方式启动的其他各种 shell 命令,并且一切都应该按预期工作
怎么运行的:
根据:执行wait4path /path && command
意味着command
只有当wait4path
结束并无错误退出时才会运行,并且只有当/path
是可用路径时才会发生这种情况,因此我们可以安全地告诉dynamic_pager
使用该卷进行交换文件
1)正如手册页中所写launchd.plist
,键Program
和ProgramArguments
被映射到一个execvp
调用,这意味着除了数组中第一个字符串之外的所有内容都被视为数组中第一个字符串的参数,即要运行的程序;
2)正如手册页中所写bash
,有一个bash -c <string>
选项可以运行作为命令传递的字符串
1+2=3)在 launchd plist 中使用此命令行会发生什么?
/bin/bash -c "wait4path /Volumes/Swap/ && /sbin/dynamic_pager -F /Volumes/Swap/.vm/swapfile"
/bin/bash
是要运行的程序,-c
是第一个参数,双引号字符串是第二个参数
我猜它应该完全按照你的解决方案工作,没有中间脚本:launchd
将启动服务,等待给定的路径然后启动dynamic_pager
..
请注意:
* 如果你bash -c
在终端中运行,则要执行的字符串应该用双引号引起来,但它是不是在 plist 文件中用双引号引起来!(我猜是因为它已经用正确的标签声明为字符串)
* 字符串中的两个必须在 plist 文件中&
更改为&
附言:与往常一样,请自行承担风险,对于您使用此设置时可能遇到的问题,我概不负责!
感谢您与我们分享您的作品
答案4
您可以使用 wait4path 等待卷挂载;否则,launchd 将一遍又一遍地重新启动您的 dynamic_pager_init 脚本,直到它完成......