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

Kri*_*rgs 98 ram-usage cache freeze ram

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

我是否启用或禁用交换并不重要,每当实际使用的 RAM 量开始接近最大值并且几乎没有剩余空间用于磁盘缓存时,系统变得完全没有响应。

磁盘疯狂旋转,有时在长时间等待 10-30 分钟后它会解冻,有时不会(或者我没有耐心)。有时,如果我迅速采取行动,我可以设法缓慢打开控制台并杀死一些消耗 ram 的应用程序,例如浏览器,并且系统几乎立即解冻。

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

如果使用加载在磁盘缓存中的大文件(500MB+),并且显然之后系统无法足够快地卸载它们,那么问题可以非常快地解决。

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

现在我不得不一直生活在恐惧中,当做某事时计算机可能会死机,我通常必须重新启动它,如果它真的用完了内存,我更喜欢它只是杀死一些用户空间应用程序,例如浏览器(最好是我能以某种方式标记先杀死哪个)

尽管谜团是为什么在这种情况下不交换保存我。

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

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

Kri*_*rgs 80

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

sysctl -w vm.min_free_kbytes=65536
Run Code Online (Sandbox Code Playgroud)

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

这会强制计算机尝试保持此数量的 RAM 可用,并且这样做会限制缓存磁盘文件的能力。当然,它仍然会尝试缓存它们并立即将它们交换出去,因此您也应该限制交换:

sysctl -w vm.swappiness=5
Run Code Online (Sandbox Code Playgroud)

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

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

现在有足够的保留空间来避免内存不足,这显然是问题所在(因为不再像以前那样冻结了)。

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

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


您可能希望通过将这些设置添加到以下内容中来使这些设置永久化/etc/sysctl.conf

vm.swappiness=5
vm.min_free_kbytes=65536
Run Code Online (Sandbox Code Playgroud)

  • 为了加速这个计算,你的总内存可以从 `free --kilo` 中获得,你的处理器数量可以使用 `nproc` 获得,你可以使用 bash 将它们相加,例如 `echo $((8242745 * 0.06 / 4))` (3认同)
  • “[vm.min_free_kbytes] 强制计算机尝试保持此数量的 RAM 空闲,这样做会限制缓存磁盘文件的能力。” -- 抱歉打扰,但这与 `vm.min_free_kbytes` 的作用完全无关。当处于高系统内存争用时,它充当保留的页面块以减轻原子(即填充或终止/非`__GFP_WAIT`)分配。在这里提出它*可能*确实有意义(因为这些停顿可能与系统内存争用有关),但肯定不是由于本答案中描述的原因。 (2认同)

Dal*_*son 10

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

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

相反,问题在于安装期间交换分区的 UUID 与安装后不同。所以我的交换从未启用,我的机器会在使用几个小时后锁定。

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

sudo blkid
Run Code Online (Sandbox Code Playgroud)

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

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

  • 非常感谢!近一年来,我一直在与这个令人难以置信的令人愤怒的错误作斗争,并且已经尝试了*一切* 来修复它。为什么 Linux 有这种行为?看起来它应该表现得像没有交换一样,只需调用 OOM-killer。相反,它似乎假装有交换,但实际上并没有交换出来(因为实际上没有,因为它配置不正确)。 (3认同)

小智 8

没有什么对我有用!!

所以我写了一个脚本来监控内存使用情况。如果内存消耗增加阈值,它将首先尝试清除 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)
Run Code Online (Sandbox Code Playgroud)

将代码保存在一个文件中,比如 save_hang.py。运行脚本如下:

sudo python save_hang.py
Run Code Online (Sandbox Code Playgroud)

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

sudo apt-get install python3-tk
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助...

  • 回过头来请注意,这个脚本非常有效!我的桌面系统(没有交换...别问)在过去一个月没有冻结,每次有东西被杀死时我都会收到一个方便的通知。 (2认同)

小智 5

我知道这个问题很老,但我在 Acer C720 Chromebook 上的 Ubuntu (Chrubuntu) 14.04 中遇到了这个问题。我尝试了 Krišj?nis Nesenbergs 解决方案,它有点工作,但有时仍然崩溃。

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

sudo apt-get install zram-config
Run Code Online (Sandbox Code Playgroud)

之后我能够通过修改/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))
Run Code Online (Sandbox Code Playgroud)

我用 1 替换了 2,以使 zram 大小与我拥有的 ram 大小相同。自从这样做以来,我不再有卡顿或系统无响应的情况。