Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
Re: memory usage with + / e glob qualifiers
- X-seq: zsh-workers 55201
- From: Mikael Magnusson <mikachu@xxxxxxxxx>
- To: zsh-workers@xxxxxxx
- Subject: Re: memory usage with + / e glob qualifiers
- Date: Fri, 9 Oct 2026 19:18:26 +0200
- Arc-authentication-results: i=1; mx.google.com; arc=none
- Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20260327; h=content-transfer-encoding:to:subject:message-id:date:from :in-reply-to:references:mime-version:dkim-signature; bh=5cDg2hTzAqS3IYX4VBM+tKf1+gmrSCk/0ps7F+0wY2E=; fh=SbTlPuNNxBzTkRlwWtqw/TXBY0HvGvtE97RpPp3sJPM=; b=OSJSqtkn27b0Ec+NO1tOJd2SHHvNThmWidaTp3yvh34cZctjAiq25OarLtcFbWxe6e mQ6VDAiDmXKb/AP/oYX5NrfHbh3vCaei6TIE9i4FZ/nWDRm/ElNuoBKzdCcuGQpu+EHK WvQIVhK4hNUg97tbPKtLEeMI20lWpAs4gOEHFvj97bgv3Fwf38+dM26VJyw5rg/4P0V3 tfjYaR2p6h45n7h3jlytaqhqEC+Trg64HVJozvYrx2YGZrUfaQOehIQZF5YS0bpRZQF9 W8wubPTePlU4MebHktZCatuQuxcqxISXmaJ+4MtwYlkaQUwimD0HATlMXVV8kG09WHoX kUKg==; darn=zsh.org
- Arc-seal: i=1; a=rsa-sha256; t=1791566319; cv=none; d=google.com; s=arc-20260327; b=AgAM3CxmUd+hGiR0ir5n7yfAH46fmKXXR6h2aWpp8Gzlf0EpgCoo1rdJIrdsEEFjrg gsMNnbj7gls/ZqVjMQl89UD4VGYFiBCkAu1kaoY3zPg6r5eJZSM4EnDz2i4cJ0ANY9bK JiHl1LST6LMVbv4wDfn/nTo9BGB45qUkr+AiKanaiMp3UD0XLb08g48jux+JfzrwvWNn LevwzoSzgjj1TsV8jCcMOg7muC9FuqEINCznevlg26VIGdLIi3BnoBA2uV03+7jtI0Mt huVRMzaS+yj8fEykTqBFz5qiFhg8bvVr5C5f4z5glRm51BE+fvyeioPOkDVl27USqz7X 44LQ==
- Archived-at: <https://zsh.org/workers/55201>
- In-reply-to: <asjShDtTIy_RYZGm@chazelas.org>
- List-id: <zsh-workers.zsh.org>
- References: <asjShDtTIy_RYZGm@chazelas.org>
On Fri, Oct 9, 2026 at 1:46 PM Stephane Chazelas <stephane@xxxxxxxxxxxx> wrote:
>
> Hi,
>
> I was surprised to find out that globs such as **/*(N+false)
> that expand to nothing end up using more memory than **/*
> according to time's %M
>
> It's even worse when combined with -:
>
> $ du --count-links --inodes --summarize
> 675285 .
>
> $ (TIMEFMT=%M; time zsh -c ': **/*(N+false)')
> 225176
> $ (TIMEFMT=%M; time zsh -c ': **/*(N-+true)')
> 370828
> $ (TIMEFMT=%M; time zsh -c ': **/*')
> 159624
>
> With another glob that expands to nothing without using the +
> qualifier:
>
> $ (TIMEFMT=%M; time zsh -c ': **/*(N./)')
> 48176
>
> Similar with the e qualifier:
>
> $ (TIMEFMT=%M; time zsh -c ': **/*(N-e[])')
> 233312
>
> What could explain that?
The eprogs allocated to run your shell code are allocated on 'the
heap' (eg, the pushheap/popheap zsh uses), but nothing pops this until
the whole glob is finished, so you may get quite a high peak memory
usage. However, the result from each eprog might also be allocated on
the heap, so you can't just push/pop it around each filename being
processed.
static int
qualsheval(char *name, UNUSED(struct stat *buf), UNUSED(off_t days), char *str)
{
Eprog prog;
if ((prog = parse_string(str, 0))) { <-- eprog allocated on the heap
int ef = errflag, lv = lastval, ret;
int cshglob = badcshglob;
unsetparam("reply");
unsetparam("REPLY");
setsparam("REPLY", ztrdup(name));
badcshglob = 0;
execode(prog, 1, 0, "globqual"); <- we don't need the eprog
after this point
if ((ret = lastval))
badcshglob |= cshglob;
/* Retain any user interrupt error status */
errflag = ef | (errflag & ERRFLAG_INT);
lastval = lv;
if (!(inserts = getaparam("reply")) &&
!(inserts = gethparam("reply"))) {
char *tmp;
if ((tmp = getsparam("reply")) || (tmp = getsparam("REPLY"))) {
static char *tmparr[2];
tmparr[0] = tmp; <- but this string is allocated on
the same heap and stored in an array until after the whole glob
finishes
tmparr[1] = NULL;
inserts = tmparr;
}
}
return !ret;
}
return 0;
}
so if you want to reduce this peak memory usage, some surgery would be
required. My guess is that passing through a flag to parse_string to
do a permanent allocation so we can free prog after execode would be
the easier route, but I haven't looked into it very hard.
--
Mikael Magnusson
Messages sorted by:
Reverse Date,
Date,
Thread,
Author