计算机冻结在几乎满的RAM上,可能是磁盘缓存问题


74

我认为这个问题有点类似于线程。

无论启用还是禁用交换都无关紧要,只要实际使用的RAM量开始接近最大值并且几乎没有剩余空间用于磁盘缓存,系统就会变得完全无响应。

磁盘疯狂旋转,有时长时间等待10-30分钟后,磁盘会冻结,有时却无法冻结(否则我就失去了耐心)。有时,如果我迅速采取行动,我可以设法缓慢打开控制台并杀死一些浏览器之类的ram应用程序,并且系统几乎立即冻结。

由于这个问题,我几乎看不到交换中的任何内容,只是有时那里只有几MB,然后很快出现此问题。我没有那么有根据的猜测是,它以某种方式连接到磁盘缓存太贪婪,或者内存管理太宽松,因此当需要内存时,它不能足够快地释放并使系统饿死。

如果处理在磁盘高速缓存中加载的过时文件(500MB +),并且随后系统无法足够快地卸载它们,则可以非常快地解决问题。

任何帮助或想法将不胜感激。

现在,我不得不一直担心,当做某事时计算机可能会冻结并且我通常必须重新启动它,如果它真的用光了内存,我更希望它只是杀死一些用户空间应用程序,例如broser(最好是如果我能以某种方式标记先杀死哪个)

尽管在这种情况下,雾the是为什么不调动救我的原因。

更新:它没有挂了一段时间,但是现在我又发生了几次。现在,我一直都在屏幕上保持ram监视器,并且在发生挂起时,它仍显示约30%的可用空间(可能由磁盘缓存使用)。其他症状:如果在我正在观看视频(VLC播放器)时,声音首先停止,几秒钟后图像停止。虽然声音停止了,但是我仍然可以控制PC,但是当图像停止时,我什至无法移动鼠标,因此在等待一段时间后重新启动了鼠标。顺便说一句,当我开始观看视频时并没有发生这种情况,但是有一段时间(20分钟),即使当时浏览器和oowrite一直在第二个屏幕上打开,我当时也没有积极地做其他事情。基本上,某些事情只决定在某一时刻发生并挂起系统。

根据评论中的要求,我在挂起后立即运行dmesg。我没有发现任何古怪的东西,但不知道要看什么,所以在这里:https : //docs.google.com/document/d/1iQih0Ee2DwsGd3VuQZu0bPbg0JGjSOCRZhu0B05CMYs/edit?hl=zh_CN&authkey=CPzF7bcCC


11
这需要引起更多关注。我知道有许多错误已提交多年。
3

1
@ n3rd:这是错误
Dan Dascalescu

@KrišjānisNesenbergs:如果我错了,粘贴长文件也会使它挂起,请纠正我。
Rick2047 '17

感谢您提出这个问题并找到解决方案。请在更新中添加一个日期,否则不清楚什么有效,什么无效。我遇到了同样的问题,我一直在检查内存级别,我有16GB,计划有32GB,以查看是否可以用这种方式解决它……
Beto Aveiga

Answers:


63

要解决此问题,我发现您需要将以下设置设置为总物理RAM的5%-6%左右,再除以计算机中的内核数:

sysctl -w vm.min_free_kbytes=65536

请记住,这是每个内核的设置,因此,如果我有2GB RAM和两个Core,那么我计算出只有1GB的6%,并添加了一些额外的内容以确保安全。

这迫使计算机尝试保持此RAM可用空间,并且这样做限制了缓存磁盘文件的能力。当然,它仍然尝试缓存它们并立即将它们换出,因此您可能还应该限制交换:

sysctl -w vm.swappiness=5

(100 =尽可能频繁地交换,0 =仅在完全必要时进行交换)

结果是,Linux不再在观看时随机决定在ram中加载整个大约1GB的电影文件,并以此杀死机器。

现在有足够的保留空间来避免内存不足,而这显然是个问题(请参见不再像以前那样冻结)。

经过一天的测试-锁定已经消失了,有时会出现轻微的减速,因为缓存的频率更高,但是如果我不必每隔几个小时重新启动计算机,我就可以忍受。

这里的教训是-默认内存管理只是用例之一,尽管有些人试图提出其他建议,但并非总是最佳选择-家庭娱乐ubuntu的配置应与服务器不同。


您可能想通过将它们添加到您的目录中来使这些设置永久化/etc/sysctl.conf

vm.swappiness=5
vm.min_free_kbytes=65536

善于发现,尝试报告有关它的错误,从而有更多的问题的认识,并希望有人会拿出一个解决方案,不是随机加载整个电影
Oxwivi

谢谢,非常详细,并解释了我的问题。非常感激!
odedbd

1
好吧,我几乎尝试了所有事情,只有您的建议有所改善。谢谢
vitalii '16

1
如果我没有交换分区运行,我应该使用比5-6%大的数量吗?vm.swappiness我认为在这种情况下设置将不起作用?
加里特·米拉德

1
“ [vm.min_free_kbytes]强制计算机尝试保持此RAM量可用,并且这样做限制了缓存磁盘文件的能力。” -很抱歉,但这与做什么无关vm.min_free_kbytes__GFP_WAIT当处于高系统内存争用状态时,它充当保留的页面块,以缓解原子(即,填充或杀死/非)分配。它可能确实意义在这里提它(如可能这些摊位都涉及到系统内存争),但它肯定不会是在这个答案说明的原因。
克里斯·

9

这是我在新安装的Ubuntu 14.04中发生的。

就我而言,它与提到的sysctl问题无关。

相反,问题是交换分区的UUID在安装过程中与在安装后不同。因此,我的交换从未启用,并且我的机器在使用数小时后会锁定。

解决方案是检查交换分区的当前UUID

sudo blkid

然后sudo nano /etc/fstab将不正确的交换的UUID值替换为blkid报告的值。

一个简单的重启以影响更改,瞧。


3
非常感谢!近一年来,我一直在努力解决这个令人难以置信的令人毛骨悚然的错误,并且已经尝试了所有修复此错误的方法。为什么Linux会有这种行为?似乎应该像没有交换一样操作,而只是调用OOM杀手。取而代之的是,它看起来好像在进行交换,但实际上却无法进行交换(因为实际上没有,因为配置不正确)。
crazy2be

@ crazy2be它没有失败,它不断取得成功。即使没有任何交换,Linux仍可以调出内存中的程序和未修改的文件,然后从磁盘重新读取它们。
马丁·桑顿

4

我知道这个问题很旧,但是我在Acer C720 Chromebook的Ubuntu(Chrubuntu)14.04中遇到了这个问题。我尝试了KrišjānisNesenbergs解决方案,它虽然有些奏效,但有时仍然崩溃。

我终于找到了一种解决方案,该解决方案通过安装zram而不是在SSD上使用物理交换来工作。要安装它,我只是按照此处的说明进行操作,如下所示:

sudo apt-get install zram-config

之后,我可以通过/etc/init/zram-config.conf在第21行进行修改来配置zram交换的大小。

20: # Calculate the memory to user for zram (1/2 of ram)
21: mem=$(((totalmem / 2 / ${NRDEVICES}) * 1024))

我将2替换为1,以使zram大小与我拥有的ram大小相同。从那以后,我再也没有死机或系统无响应的情况。


zram仅当您无法安装更多RAM时才是可行的选择。如果系统在切换到SSD时速度太慢,并且没有交换就退出RAM,那么zram可能会有所帮助,直到您尝试做更多一点,其结果与没有交换而退出RAM相同。
Mikko Rantalainen

4

什么都没有为我工作!

所以我写了一个脚本来监视内存使用情况。如果内存消耗增加了阈值,它将首先尝试清除RAM缓存。您可以在脚本上配置此阈值。如果直到那时内存消耗仍未低于阈值,它将以内存消耗的降序开始杀死进程,直到内存消耗低于阈值。我已将其默认设置为96%。您可以通过在脚本中更改变量RAM_USAGE_THRESHOLD的值来进行配置。

我同意杀死消耗大量内存的进程不是完美的解决方案,但是最好杀死一个应用程序而不是丢失所有工作!如果RAM使用率增加阈值,脚本将向您发送桌面通知。如果它杀死任何进程,它也会通知您。

#!/usr/bin/env python
import psutil, time
import tkinter as tk
from subprocess import Popen, PIPE
import tkinter
from tkinter import messagebox
root = tkinter.Tk()
root.withdraw()

RAM_USAGE_THRESHOLD = 96
MAX_NUM_PROCESS_KILL = 100

def main():
    if psutil.virtual_memory().percent >= RAM_USAGE_THRESHOLD:
        # Clear RAM cache
        mem_warn = "Memory usage critical: {}%\nClearing RAM Cache".\
            format(psutil.virtual_memory().percent)
        print(mem_warn)
        Popen("notify-send \"{}\"".format(mem_warn), shell=True)
        print("Clearing RAM Cache")
        print(Popen('echo 1 > /proc/sys/vm/drop_caches',
                    stdout=PIPE, stderr=PIPE,
                    shell=True).communicate())
        post_cache_mssg = "Memory usage after clearing RAM cache: {}%".format(
                            psutil.virtual_memory().percent)
        Popen("notify-send \"{}\"".format(post_cache_mssg), shell=True)
        print(post_cache_mssg)

        if psutil.virtual_memory().percent < RAM_USAGE_THRESHOLD:
            print("Clearing RAM cache saved the day")
            return
        # Kill top C{MAX_NUM_PROCESS_KILL} highest memory consuming processes.
        ps_killed_notify = ""
        for i, ps in enumerate(sorted(psutil.process_iter(),
                                      key=lambda x: x.memory_percent(),
                                      reverse=True)):
            # Do not kill root
            if ps.pid == 1:
                continue
            elif (i > MAX_NUM_PROCESS_KILL) or \
                    (psutil.virtual_memory().percent < RAM_USAGE_THRESHOLD):
                messagebox.showwarning('Killed proccess - save_hang',
                                       ps_killed_notify)
                Popen("notify-send \"{}\"".format(ps_killed_notify), shell=True)
                return
            else:
                try:
                    ps_killed_mssg = "Killed {} {} ({}) which was consuming {" \
                                     "} % memory (memory usage={})". \
                        format(i, ps.name(), ps.pid, ps.memory_percent(),
                               psutil.virtual_memory().percent)
                    ps.kill()
                    time.sleep(1)
                    ps_killed_mssg += "Current memory usage={}".\
                        format(psutil.virtual_memory().percent)
                    print(ps_killed_mssg)
                    ps_killed_notify += ps_killed_mssg + "\n"
                except Exception as err:
                    print("Error while killing {}: {}".format(ps.pid, err))
    else:
        print("Memory usage = " + str(psutil.virtual_memory().percent))
    root.update()


if __name__ == "__main__":
    while True:
        try:
            main()
        except Exception as err:
            print(err)
        time.sleep(1)

将代码保存在一个名为save_hang.py的文件中。运行脚本为:

sudo python save_hang.py

请注意,该脚本仅与Python 3兼容,并且需要您安装tkinter软件包。您可以将其安装为:

sudo apt-get install python3-tk

希望这可以帮助...


2

我的猜测是您vm.swappiness将其设置为非常低的值,这会导致内核交换时间太晚,而留下的RAM太低,系统无法使用。

您可以通过执行以下命令显示当前的交换设置:

sysctl vm.swappiness

默认情况下,它被设置为60. Ubuntu的维基建议将其设置为10,但随时将其设置为一个较高的值。您可以通过运行以下命令进行更改:

sudo sysctl vm.swappiness=10

这将当前会话中更改它,以使其持久,您需要添加vm.swappiness = 10/etc/sysctl.conf文件中。

如果磁盘速度慢,请考虑购买新的磁盘。


实际上降低交换性可以减少问题(这种情况很少发生)。我现在保持在5点。尽管这可能是高交换性的另一个问题,因为在60岁时,我决定看电影或编辑大文件时,整个文件(几乎是一个GB)已加载到内存中,然后系统立即开始换出我当时正在使用的程序。积极使用甚至用户界面本身。我想我了解交换部分,我想要的是杀死贪婪的用户应用程序,而不是在用完ram时冻结机器。(并且优选限制缓存文件大小)
KrišjānisNesenbergs

@Krisa:当系统内存不足(RAM和交换空间)用完时,内核调用oom_kill杀死进程以节省内存。不幸的是,您无法控制目标流程。要手动触发它,请按Alt + SysRq +F。运行该dmesg命令时,您应该看到该进程的一些信息(以及进程名称+ ID)。我认为您最好购买更快的新磁盘。或升级您的RAM。
Lekensteyn 2011年

3
问题是,在计算机锁定大约30分钟之前,没有调用oom_kill。另外-是否至少有办法知道哪个进程将首先被杀死?
KrišjānisNesenbergs

2
我有2GB内存,硬盘驱动器是5400rpm。我真的不认为这是一个如此老的系统,可以在一个监视器上观看一些视频并在另一个监视器上浏览一些20-30个选项卡时冻结半个小时。实际上,如果我能一直访问控制台并终止某些进程,我会很高兴-是否有一种方法可以使用户输入和终端具有超高优先级,从而在系统冻结时起作用?
KrišjānisNesenbergs

1
无论如何-交换和RAM的数量有点题外话。问题是,即使禁用了交换功能,该系统也会长时间不响应,此后有时仍会运行该程序(因此它设法在某处找到内存),而其他时候运行oom_killer。该系统应该能够告诉它ram已经用完了,只是不要让我运行更多的东西。那么,有什么方法可以阻止这些冻结或将用户输入的优先级设置得如此之高,以便我可以在发生这种情况时切换到控制台并自己杀死一些进程?
KrišjānisNesenbergs

2

我已经为这个问题苦苦挣扎了很长时间,但现在似乎可以在我的笔记本电脑上解决了。

如果没有其他答案对您有用(我尝试了大多数答案),请使用min_free_kbytes玩游戏,以在计算机开始交换时在RAM中拥有更多空间(就在达到可用RAM上的最小值之前)。

我有16GB的RAM,但比现在更早,内存已满,然后停止响应10至30分钟,直到交换了一些东西。

至少对我来说,将min_free_kbytes值设置为建议值以上可以大大加快交换过程。

对于16GB RAM,请尝试以下操作:

vm.min_free_kbytes=500000

要设置此值,请参见其他答案,或只是将其搜索出来:)


0

我经常从活动的Ubuntu SD卡中运行一台笔记本电脑,笔记本电脑上有一个小的ext4存储分区和一个交换文件。当几乎所有的RAM都被使用并且swappiness值太低时(有时我宁愿尽可能地将硬盘完全关闭,因为它很吵),Linux性能对我来说往往会下降,以至于TTY1杀死Firefox需要15分钟。

/proc/sys/vm/vfs_cache_pressure从默认值100 提高到6000似乎可以防止这种情况的发生。但是,内核文档警告不要这样做,说

Increasing vfs_cache_pressure significantly beyond 100 may have negative
performance impact. Reclaim code needs to take various locks to find freeable
directory and inode objects. With vfs_cache_pressure=1000, it will look for
ten times more freeable objects than there are.

我不能完全确定这样做的副作用,因此我会谨慎执行。


vfs_cache_pressure接近10(即远小于100)并设置得min_free_kbytes更高,您可能会遇到更好的结果。请注意,如果设置min_free_kbytes得太高,内核OOM杀手将杀死所有人!
Mikko Rantalainen

@MikkoRantalainen我已经提高min_free_kbytes到262144,并且我观察到降低vfs_cache_pressure具有相反的效果-将其降低到100以下会使系统变得无响应更快。我不确定为什么会这样。
Hitechcomputergeek

通常,增加值vfs_cache_pressure会导致在缓存文件内容之前引发麻烦,因此,如果超过100,则总体性能通常会受到影响。如果您能找出从Ubuntu Live CD开始重新制作崩溃或挂起系统的步骤,然后内核开发人员可以找出根本原因。对我来说,挂起没有任何警告。我最好的猜测是,在OOM Killer释放足够的RAM之前,内核因OOM而挂起。我现在正在运行min_free_kbytes = 100000,admin_reserve_kbytes = 250000和user_reserve_kbytes = 500000。
Mikko Rantalainen

(续)即使我的swappiness = 5和vfs_cache_pressure = 20,我也没有因上述配置而崩溃。系统具有16 GB的RAM和8 GB的SSD交换空间。另一个系统具有32 GB的RAM和零交换,它似乎随机遭受相同的问题-在系统感觉缓慢后按Alt + SysRq + f似乎有帮助,所以我想OOM Killer的运行速度是否足够快,系统就不会挂起。
Mikko Rantalainen
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.