1.背景
公司产业使用nebula图数据库的过程中总是遇到报错内存Used memory(178593436KB) hits the high watermark(0.800000) of total system memory(196268364KB), 导出无法执行数据操作
2.问题排查
查询官网博客发现解决办法是调整该参数 --system_memory_high_watermark_ratio = 0.9 ,默认为0.8,该参数的主要作用是判定系统使用内存占比超过80%时触发,导致数据库无法查询。那么在代码中是如何判断的,如下
3.具体分析
system_memory_high_watermark_ratio
是一个用于设置系统内存高水位线比例的标志(flag),在代码中主要用于判断系统内存的使用是否达到了设定的高水位线,以此来监控系统内存的使用情况,避免内存过度使用引发的问题。
在不同的场景下,system_memory_high_watermark_ratio
会被用于不同的判断逻辑:
- 在
MemoryUtils::hitsHighWatermark
函数中,该比例用于判断当前系统内存的使用量是否超过了设定的高水位线。如果超过了,说明系统内存使用量已经达到了一个较高的水平,可能需要采取一些措施,如限制内存分配、记录日志或者抛出异常等。 - 在
Iterator::hitsSysMemoryHighWatermark
函数和Executor::checkMemoryWatermark
函数中,会根据MemoryUtils::kHitMemoryHighWatermark
的值(该值是在MemoryUtils::hitsHighWatermark
函数中根据system_memory_high_watermark_ratio
判断后设置的)来决定是否抛出异常或返回错误状态,从而避免在内存使用过高的情况下继续执行可能会导致内存耗尽的操作。
代码中根据服务器的哪些信息去判断
代码中根据服务器的不同信息来判断内存使用是否达到高水位线,具体取决于服务器是否为容器化环境(通过 FLAGS_containerized
标志判断):
- 非容器化环境(
FLAGS_containerized
为false
)
在非容器化环境下,代码通过读取 /proc/meminfo
文件来获取系统内存信息:
FileUtils::FileLineIterator iter("/proc/meminfo", &reMemAvailable);
std::vector<uint64_t> memorySize;
for (; iter.valid(); ++iter) {
auto& sm = iter.matched();
memorySize.emplace_back(std::stoul(sm[2].str(), nullptr) << 10);
}
std::sort(memorySize.begin(), memorySize.end());
if (memorySize.size() >= 2u) {
total = memorySize.back();
available = memorySize[memorySize.size() - 2];
} else {
return false;
}
total
:表示系统的总内存大小,通过读取/proc/meminfo
文件并解析其中的信息,将最大的内存值作为总内存。available
:表示系统当前可用的内存大小,通过读取/proc/meminfo
文件并解析其中的信息,将第二大的内存值作为可用内存。
- 容器化环境(
FLAGS_containerized
为true
)
在容器化环境下,代码通过读取 cgroup 文件来获取内存信息:
bool cgroupsv2 = FileUtils::exist(FLAGS_cgroup_v2_controllers);
std::string statPath =
cgroupsv2 ? FLAGS_cgroup_v2_memory_stat_path : FLAGS_cgroup_v1_memory_stat_path;
FileUtils::FileLineIterator iter(statPath, &reTotalCache);
uint64_t cacheSize = 0;
for (; iter.valid(); ++iter) {
auto& sm = iter.matched();
cacheSize += std::stoul(sm[2].str(), nullptr);
}
std::string limitPath =
cgroupsv2 ? FLAGS_cgroup_v2_memory_max_path : FLAGS_cgroup_v1_memory_max_path;
auto limitStatus = MemoryUtils::readSysContents(limitPath);
NG_RETURN_IF_ERROR(limitStatus);
uint64_t limitInBytes = std::move(limitStatus).value();
std::string usagePath =
cgroupsv2 ? FLAGS_cgroup_v2_memory_current_path : FLAGS_cgroup_v1_memory_current_path;
auto usageStatus = MemoryUtils::readSysContents(usagePath);
NG_RETURN_IF_ERROR(usageStatus);
uint64_t usageInBytes = std::move(usageStatus).value();
total = static_cast<double>(limitInBytes);
available = static_cast<double>(limitInBytes - usageInBytes + cacheSize);
total
:表示容器的内存限制大小,通过读取 cgroup 中的memory.max
文件(cgroups v2)或memory.limit_in_bytes
文件(cgroups v1)来获取。available
:表示容器当前可用的内存大小,通过读取 cgroup 中的memory.current
文件(cgroups v2)或memory.usage_in_bytes
文件(cgroups v1)来获取,并加上缓存大小(通过解析memory.stat
文件获取)。
4.最终判断逻辑
无论在容器化环境还是非容器化环境下,最终都会根据以下公式判断内存使用是否达到高水位线:
auto hits = (1 - available / total) > FLAGS_system_memory_high_watermark_ratio;
如果 hits
为 true
,则表示系统内存使用已经达到了高水位线,会记录相应的日志信息。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· AI与.NET技术实操系列(六):基于图像分类模型对图像进行分类