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

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

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

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

磁盘疯狂旋转,有时经过 10-30 分钟的漫长等待后才会解冻,有时则不会(或者我失去了耐心)。有时如果我行动迅速,我可以设法慢慢打开控制台并关闭一些占用内存的应用程序(如浏览器),系统几乎立即解冻。

由于这个问题,我几乎看不到交换区中有任何东西,只有偶尔有几 MB 空间,然后不久后这个问题就出现了。我不太有根据的猜测是,它与磁盘缓存太贪婪或内存管理太宽松有关,因此当需要内存时,它不能足够快地释放,导致系统资源匮乏。

如果处理加载到磁盘缓存中的大文件(500MB+),问题就会很快出现,显然之后系统无法足够快地卸载它们。

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

现在我不得不生活在恐惧之中,当做某件事的时候,电脑就会死机,我通常不得不重新启动它,如果它真的耗尽了内存,我更希望它能杀死一些用户空间应用程序,比如浏览器(最好是我能以某种方式标记先杀死哪个)

尽管令人费解的是,为什么在这种情况下 swap 不能拯救我。

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

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

答案1

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

sysctl -w vm.min_free_kbytes=65536

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

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

sysctl -w vm.swappiness=5

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

结果是,Linux 不再在观看电影时随机决定在 RAM 中加载约 1GB 的整个电影文件,并因此导致机器死亡。

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

经过一天的测试后,死机现象消失了,有时会出现轻微的速度减慢,因为内容被更频繁地缓存,但如果我不必每隔几个小时重新启动计算机,我可以忍受。

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


您可能希望通过/etc/sysctl.conf如下方式将这些设置添加到您的设置中以使它们永久生效:

vm.swappiness=5
vm.min_free_kbytes=65536

答案2

我在新安装的 Ubuntu 14.04 中遇到了这种情况。

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

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

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

sudo blkid

然后sudo nano /etc/fstab用 blkid 报告的 UUID 值替换错误的交换的 UUID 值。

简单的重启即可使更改生效,瞧!

答案3

对我没什么用!!

所以我写了一个脚本来监控内存使用情况。如果内存消耗超过阈值,它将首先尝试清除 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

希望这可以帮助...

答案4

我的猜测是,您将您的vm.swappiness值设置得太低,这导致内核交换得太晚,导致系统无法使用太低的 RAM。

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

sysctl vm.swappiness

默认情况下,该值设置为 60。Ubuntu 维基建议将其设置为 10,但也可以将其设置为更高的值。您可以通过运行以下命令来更改它:

sudo sysctl vm.swappiness=10

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

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

相关内容