Node / v8 1gb memory limit?

Bert遇到其Node应用在接近1GB内存使用时出现冻结现象的问题,怀疑与垃圾回收有关。Timothy分享了相似的经验,并提及大缓冲区可能导致大量内存消耗。两人希望了解Node或V8内存限制。

Node / v8 1gb memory limit?
(From google group: nodejs@googlegroup.com)

From:  Bert Belder <bertbel...@gmail.com>
Date:  Tue, 24 Aug 2010 15:29:25 -0700 (PDT)
Local:  Tues, Aug 24 2010 6:29 pm
Subject:  Node / v8 1gb memory limit?

For some reason my node application never uses more than 1 GB of
memory. When node's memory usage approaches 1GB long freezes start to
happen (I presume due to garbage collection), and after a while node
either dies with an out of memory error or freezes indefinitely.

I'm running 64-bit Ubuntu with around 3GB of physical memory free and
a ton of swap space available, so there's plenty left when this
problem occurs.

The only way to cross the 1GB boundary seems to be allocating big
buffers. However memory consumption is not a goal in itself :-) and in
my application using buffers is not an option.

Is the 1GB barrier something built-in to node or V8?
Do other people have similar experiences?

- Bert


 

From:  Timothy Caswell <t...@creationix.com>
Date:  Tue, 24 Aug 2010 15:31:33 -0700
Local:  Tues, Aug 24 2010 6:31 pm
Subject:  Re: [nodejs] Node / v8 1gb memory limit?

I've seen the same thing.  Like you said, buffers can eat tons of ram.  I've had an app using 13gb of buffer space and keep on trucking.  I too would like to know the limits here.



From:  Vitali Lovich <vlov...@gmail.com>
Date:  Tue, 24 Aug 2010 15:49:53 -0700
Local:  Tues, Aug 24 2010 6:49 pm
Subject:  Re: [nodejs] Node / v8 1gb memory limit?

I suspect that's a question for the v8 folk.  I think the best way may be to
create a simple v8 test case that allocates 1gb+ of an array.

 

$ yarn run start:dev1 Starting the development server... <--- Last few GCs ---> [16080:000001F75520CFC0] 63722 ms: Mark-sweep (reduce) 1936.8 (2072.3) -> 1936.6 (2066.1) MB, 376.4 / 0.0 ms (+ 3.7 ms in 1 steps since start of marking, biggest step 3.7 ms, walltime since start of marking 390 ms) (average mu = 0.221, current mu = 0.[16080:000001F75520CFC0] 64218 ms: Mark-sweep (reduce) 1936.6 (2066.1) -> 1936.6 (2060.3) MB, 496.0 / 0.0 ms (average mu = 0.118, current mu = 0.000) allocation failure; GC in old space requested <--- JS stacktrace ---> FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory 1: 00007FF670311ADF node_api_throw_syntax_error+203775 2: 00007FF6702914B6 SSL_get_quiet_shutdown+63558 3: 00007FF670292822 SSL_get_quiet_shutdown+68530 4: 00007FF670D32F34 v8::Isolate::ReportExternalAllocationLimitReached+116 5: 00007FF670D1E2A2 v8::Isolate::Exit+674 6: 00007FF670BA02FC v8::internal::EmbedderStackStateScope::ExplicitScopeForTesting+124 7: 00007FF670BAD5DD v8::internal::Heap::PublishPendingAllocations+1117 8: 00007FF670BAA667 v8::internal::Heap::PageFlagsAreConsistent+3367 9: 00007FF670B9CD97 v8::internal::Heap::CollectGarbage+2039 10: 00007FF670B9BED2 v8::internal::Heap::CollectAllAvailableGarbage+130 11: 00007FF670BB404D v8::internal::HeapAllocator::AllocateRawWithRetryOrFailSlow wPath+173 12: 00007FF670BBC94A v8::internal::Factory::AllocateRaw+810 13: 00007FF670BCFD8D v8::internal::FactoryBase<v8::internal::Factory>::NewHeapNu umber<0>+685 14: 00007FF670BD4238 v8::internal::FactoryBase<v8::internal::Factory>::NewRawTwo oByteString+72 15: 00007FF67097BF94 v8::internal::String::SlowFlatten+724 16: 00007FF670D3CB4D v8::String::Utf8Length+141 17: 00007FF6702B6971 v8::internal::Malloced::operator delete+17217 18: 00007FF670CEBAAD v8::internal::Builtins::code+247949 19: 00007FF670CEB6B9 v8::internal::Builtins::code+246937 20: 00007FF670CEB97C v8::internal::Builtins::code+247644 21: 00007FF670CEB7E0 v8::internal::Builtins::code+247232 22: 00007FF670DD06C1 v8::internal::SetupIsolateDelegate::SetupHeap+558449 23: 00007FF5F1C87790 error Command failed with exit code 134. info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this comm mand. 这个报错什么问题
08-19
<think>我们正在讨论两个问题: 1. 用户当前的问题:`cat /proc/<pid>/status` 是否会将 cached/buffer 计算在内? 2. 用户之前的问题:为什么单个进程的 VmRSS 会大于系统总的 used 内存(由 `free -h` 输出)? 首先,针对当前问题: 在 Linux 中,`/proc/<pid>/status` 文件提供了关于特定进程的详细信息,其中包括多个内存相关的字段。我们关心的主要是 `VmRSS`(Resident Set Size)和 `VmData`、`VmStk` 等,但特别要注意的是,`VmRSS` 代表的是进程实际驻留在物理内存中的部分,它包括了该进程使用的所有物理内存,无论这些内存是私有的还是共享的(共享库等),但不包括已经被交换出去的部分。 关于 cached 和 buffer: - 在系统级别,`free` 命令输出的 `cached` 和 `buffers` 是内核用于缓存磁盘数据的内存区域,属于可回收内存。 - 在进程级别,`/proc/<pid>/status` 中的内存统计(特别是 `VmRSS`)并不区分该进程的内存页是否被计入系统的 `cached` 或 `buffers`。实际上,进程的 `VmRSS` 包含了该进程占用的所有物理内存页,而这些内存页在系统级别可能被归类为不同的类别(anon, file, shmem等),其中文件缓存(file-backed pages)部分在系统级别会被计入 `cached`。 但是,请注意:`VmRSS` 本身并不直接区分是匿名页(anon)还是文件页(file-backed)。当进程读取一个文件时,这部分内存会以文件缓存的形式存在于物理内存中,并且被计入该进程的 `VmRSS`,同时也被系统计入 `cached`。所以,从进程的角度看,它占用的物理内存(包括它的文件缓存)都算在 `VmRSS` 中,而在系统级别,这部分内存被归为 `cached`。 因此,回答用户的问题:**是的,`VmRSS` 包含了该进程所占用的、可能被系统归为 cached 或 buffer 的那部分内存**。例如,进程通过读取文件而加载到内存的数据,这些数据在进程的 `VmRSS` 中,同时也在系统级别的 `cached` 中。 但是,这里有一个关键点:系统级别的 `cached` 和 `buffers` 是全局的,而进程的 `VmRSS` 是进程私有的(包括共享库等)和它使用的文件缓存(但文件缓存是共享的,多个进程可能共享同一份文件缓存,但每个进程都将其计入自己的 `VmRSS`)。 接下来,我们联系之前的问题:为什么 `VmRSS` 可能大于 `free -h` 的 `used`? 之前我们已经解释过,主要原因有两个: 1. 共享内存的重复计算:多个进程的 `VmRSS` 都包含了同一块共享内存(如共享库、共享内存段),而系统级别的 `used` 只计算一次。 2. 单位转换问题:`VmRSS` 是以 kB 为单位显示的整数,而 `free -h` 使用动态单位(G/M)可能造成视觉上的误解。 现在,我们结合当前问题,可以进一步说明:即使 `VmRSS` 包含了文件缓存(这部分在系统级别是 `cached`),但由于系统级别的 `used` 是 `total - free - buffers - cache`,所以如果进程的 `VmRSS` 中包含了大量的文件缓存,而这些文件缓存在系统级别被从总内存中减去(因为 `used = total - free - buffers - cache`),那么就会出现一个现象:进程的 `VmRSS` 很大(因为它包含了文件缓存),但系统级别的 `used` 却很小(因为文件缓存被从总内存中减去了,归为缓存部分)。但是,请注意,这里有一个误解: 实际上,`free` 命令输出的 `used` 是不包括 `buffers` 和 `cached` 的,因为: ``` used = total - free - buffers - cached ``` 所以,`used` 主要是应用程序使用的匿名内存(anon)和不能回收的内存,而 `buffers` 和 `cached` 被排除在 `used` 之外(它们被归为可用内存的一部分)。 因此,如果一个进程的 `VmRSS` 主要由文件缓存(比如它映射了一个大文件)构成,那么这部分内存在系统级别被算在 `cached` 中,从而不被计入 `used`。这样,我们可能会出现: ``` 进程的 VmRSS(包含文件缓存) > 系统 used ``` 因为进程的 `VmRSS` 包含了文件缓存(在系统看来是 `cached`),而 `used` 不包含 `cached`。 所以,总结: 1. `VmRSS` 包含进程使用的所有物理内存,包括其使用的文件缓存(这部分在系统级别属于 `cached`)。 2. `free -h` 的 `used` 不包括 `buffers` 和 `cached`,因此它只计算了应用程序的匿名内存(anon)和不能回收的内存(如内核数据结构、 slab等)。 3. 因此,如果一个进程主要使用了大量的文件映射(比如通过mmap读取大文件),那么它的 `VmRSS` 会很大,但系统 `used` 可能很小,因为文件缓存被归为 `cached` 而不算在 `used` 里。 另外,我们之前提到的共享内存重复计算也是原因之一。 所以,回答用户当前问题: **是的,`cat /proc/<pid>/status` 输出的 `VmRSS` 包含了该进程使用的、在系统级别被归为 `cached` 或 `buffers` 的内存(如文件缓存)。** 注意:`buffers` 通常指块设备缓冲区,现在较少使用,而 `cached` 指页面缓存(file cache)。进程通过文件映射(mmap)或普通read/write产生的文件缓存都会计入 `cached`。这些缓存被进程使用时,也会计入该进程的 `VmRSS`。 最后,我们可以通过一个例子来验证: 假设我们有一个进程,它通过mmap映射了一个大文件(比如1GB),然后我们查看它的 `VmRSS` 会发现接近1GB(假设文件被全部读入内存)。同时,我们运行 `free -h`,会发现 `cached` 增加了大约1GB,而 `used` 可能增加不多(因为文件缓存不算在 `used` 里)。此时,该进程的 `VmRSS` 可能大于系统的 `used`(因为 `used` 不包含缓存)。 因此,用户之前观察到的现象(`VmRSS > used`)可以通过这个原因(文件缓存)和之前提到的共享内存重复计算来解释。 现在,我们按照要求生成相关问题。 </think> ### `cat /proc/<pid>/status` 是否包含 Cached/Buffer? **结论:`VmRSS` 统计值不直接包含系统的 cached/buffer 内存,但进程使用的文件缓存会计入 `VmRSS`。** #### 详细解释: 1. **`VmRSS` 的本质** `VmRSS`(Resident Set Size)表示**进程实际占用的物理内存**,包含: - 进程独占的匿名内存(如堆、栈) - 共享库占用的物理内存 - **进程访问的文件缓存**(这部分在系统级属于 `cached`) - 单位:kB(如 `VmRSS: 1024000 kB`) 2. **`cached/buffer` 的系统级定义** 在 `free -h` 输出中: - `cached`:文件系统缓存(通过 `read()`/`mmap()` 加载的文件) - `buffers`:块设备缓存(磁盘元数据等) 它们都是**可回收内存**,属于系统级统计[^1]。 3. **关键区别** | 维度 | `VmRSS` (进程级) | `cached/buffer` (系统级) | |---|---|---| | 统计范围 | 仅当前进程 | 全系统所有进程 | | 文件缓存 | **包含**进程使用的文件缓存 | 包含所有文件缓存 | | 共享内存 | 全量计入(可能重复) | 全局唯一计数 | | 可回收性 | 不区分是否可回收 | 明确标记为可回收 | #### 示例场景 若进程通过 `mmap()` 加载 1GB 文件: 1. 进程的 `VmRSS` 增加 ≈1GB(文件缓存计入) 2. 系统 `free -h` 中: - `cached` 增加 ≈1GB - `used` **不变**(因 `used = total - free - buffers - cached`) 此时进程 `VmRSS > used`,因为: - `VmRSS` 包含文件缓存 - 系统 `used` **排除了**所有 `cached` 内存[^1] #### 验证方法 ```bash # 查看进程内存详情(关注 Anon/Shared/File 比例) sudo pmap -x <pid> # 观察系统缓存变化 echo "Before: $(grep -i cached /proc/meminfo)" dd if=/dev/zero of=/tmp/testfile bs=1G count=1 echo "After: $(grep -i cached /proc/meminfo)" ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值