Skip to content

Commit c45de84

Browse files
committed
fix(cli): configure v8 isolate with cgroups-constrained memory limit
This change configures V8 isolates to respect memory limits imposed by cgroups on Linux. It adds support for detecting both cgroups v1 and v2 memory limits, enabling Deno to properly adapt to containerized environments with memory constraints. When cgroups information is unavailable or not applicable, it falls back to using the system's total memory as before.
1 parent a33dae6 commit c45de84

File tree

1 file changed

+59
-5
lines changed

1 file changed

+59
-5
lines changed

cli/lib/worker.rs

+59-5
Original file line numberDiff line numberDiff line change
@@ -130,11 +130,65 @@ pub fn get_cache_storage_dir() -> PathBuf {
130130
/// Instead probe for the total memory on the system and use it instead
131131
/// as a default.
132132
pub fn create_isolate_create_params() -> Option<v8::CreateParams> {
133-
let maybe_mem_info = deno_runtime::deno_os::sys_info::mem_info();
134-
maybe_mem_info.map(|mem_info| {
135-
v8::CreateParams::default()
136-
.heap_limits_from_system_memory(mem_info.total, 0)
137-
})
133+
#[cfg(any(target_os = "android", target_os = "linux"))]
134+
{
135+
get_memory_limit_linux().map(|memory_limit| {
136+
v8::CreateParams::default()
137+
.heap_limits_from_system_memory(memory_limit, 0)
138+
})
139+
}
140+
#[cfg(not(any(target_os = "android", target_os = "linux")))]
141+
{
142+
let maybe_mem_info = deno_runtime::deno_os::sys_info::mem_info();
143+
maybe_mem_info.map(|mem_info| {
144+
v8::CreateParams::default()
145+
.heap_limits_from_system_memory(mem_info.total, 0)
146+
})
147+
}
148+
}
149+
150+
/// Get memory limit with cgroup (either v1 or v2) taken into account.
151+
#[cfg(any(target_os = "android", target_os = "linux"))]
152+
fn get_memory_limit_linux() -> Option<u64> {
153+
let system_total_memory =
154+
deno_runtime::deno_os::sys_info::mem_info().map(|mem_info| mem_info.total);
155+
156+
let Ok(self_cgroup) = std::fs::read_to_string("/proc/self/cgroup") else {
157+
return system_total_memory;
158+
};
159+
160+
let limit = match self_cgroup.strip_prefix("0::/") {
161+
Some(cgroup_v2_relpath) => {
162+
// cgroup v2
163+
let limit_path = std::path::Path::new("/sys/fs/cgroup")
164+
.join(cgroup_v2_relpath)
165+
.join("memory.max");
166+
std::fs::read_to_string(limit_path)
167+
.ok()
168+
.and_then(|s| s.trim().parse::<u64>().ok())
169+
}
170+
None => {
171+
// cgroup v1
172+
let Some(cgroup_v1_relpath) = self_cgroup.lines().find_map(|l| {
173+
let split = l.split(":").collect::<Vec<_>>();
174+
if split.get(1) == Some(&"memory") {
175+
split.get(2)
176+
} else {
177+
None
178+
}
179+
}) else {
180+
return system_total_memory;
181+
};
182+
let limit_path = std::path::Path::new("/sys/fs/cgroup/memory")
183+
.join(cgroup_v1_relpath)
184+
.join("memory.limit_in_bytes");
185+
std::fs::read_to_string(limit_path)
186+
.ok()
187+
.and_then(|s| s.trim().parse::<u64>().ok())
188+
}
189+
};
190+
191+
limit.or(system_total_memory)
138192
}
139193

140194
#[derive(Debug, thiserror::Error, deno_error::JsError)]

0 commit comments

Comments
 (0)