~을 위한벤치마킹, 다음 명령을 실행합니다.
for i in {1..100000000}; do
echo "$i" line >> file
done
불다중괄호 확장그리고 목록을 1 2 3 4 5 6 ... 100000000
메모리에 저장합니다.
제 생각엔 이게 언젠가는 어떻게든 공개될 것 같아요. 결국 임시 변수입니다. 며칠이 지났지만 bash
프로세스는 여전히 17.9GB의 메모리를 차지했습니다.
bash에서 이러한 임시 변수를 강제로 지울 수 있나요? unset
변수 이름을 모르기 때문에 사용할 수 없습니다 . (분명히 unset i
도움이 되지 않음)
물론 한 가지 해결책은 셸을 닫고 새 셸을 여는 것입니다.
저도 bash 메일링 리스트에 이 질문을 올렸는데 도움이 되는 답변을 받았습니다.쳇 램지:
이것은 메모리 누수가 아닙니다. Malloc 구현은 메모리를 커널로 다시 릴리스할 필요가 없습니다. bash malloc(및 기타)은 제한된 상황에서만 그렇게 합니다. mmap 또는 sbrk를 사용하여 커널에서 얻은 메모리와 malloc을 통해 캐시에 저장된 메모리는 누수를 구성하지 않습니다. 누수는 애플리케이션이나 malloc 자체가 더 이상 처리할 수 없는 메모리입니다.
malloc()은 기본적으로 애플리케이션과 커널 사이의 캐시입니다. 커널에 메모리를 반환하는 시기와 방법을 결정합니다.
답변1
그래서 테스트에서 이 작업을 수행했는데, 메모리를 많이 소모했습니다. 또한 의도적으로 더 작은 숫자를 사용했습니다. bash
이러한 리소스를 며칠 동안 묶어두는 것은 다소 짜증스러울 수 있다고 생각합니다 .
ps -Fp "$$"; : {1..10000000}; ps -Fp "$$"
UID PID PPID C SZ RSS PSR STIME TTY TIME CMD
mikeserv 32601 4241 0 3957 3756 4 08:28 pts/1 00:00:00 bash -l
UID PID PPID C SZ RSS PSR STIME TTY TIME CMD
mikeserv 32601 4241 59 472722 1878712 4 08:28 pts/1 00:00:28 bash -l
보시다시피 이는 프로세스에서 소비하는 리소스에 큰 영향을 미칩니다. 글쎄, 나는 이것을 명확히 하려고 노력할 것이다. 그러나 내가 아는 한, 쉘 프로세스를 다른 쉘 프로세스로 교체해야 할 것이다.
먼저 보여드리기 위해 마커 변수를 설정하겠습니다. 참고: 이는 export
편집 내용 이 아닙니다 .
var='just
testing
'\''
this stuff
'\'''
다음에는 $0
장기 실행 데몬이 상태를 새로 고치기 위해 가끔 수행해야 하는 작업과 동일합니다. 이것은 의미가 있습니다.
첫 번째 방법: 여기에 문서화
현재 쉘을 사용하여 새로 편집된 쉘 프로세스에 대한 Heredoc 입력 파일 설명자를 작성하겠습니다. exec
여기에는 현재 쉘에서 선언된 모든 변수가 포함됩니다. 어쩌면 다르게 할 수도 있지만 모르겠습니다 bash
.
새 셸은 -l
ogin 스위치(파일을 평소대로 가져오도록 보장 profile/rc
)와 현재 특수 셸 매개변수에 설정 및 저장되어 있는 다른 셸 옵션을 사용하여 호출됩니다 $-
. -l
ogin이 올바른 접근 방식이 아니라고 생각되면 -i
스위치를 사용하여 최소한 rc
파일을 실행해야 합니다.
exec "${0#-}" "-l$-" 3<<ENV
$(set)
ENV
좋아요 단 1초밖에 걸리지 않았습니다. 효과는 어때요?
. /dev/fd/3 2>/dev/null
echo "$var"; ps -Fp "$$"
just
testing
'
this stuff
'
UID PID PPID C SZ RSS PSR STIME TTY TIME CMD
mikeserv 32601 4241 12 4054 3800 5 08:28 pts/1 00:00:29 bash -lhimBH
보이는 대로 괜찮아요. <&3
읽을 때까지 새 쉘 프로세스의 입력을 기다립니다. 그래서 그렇게 하고 .
가져옵니다. 아마도 파일 등을 통해 새 셸에 설정된 일부 기본 읽기 전용 변수가 포함되어 있으므로 rc
일부 오류가 있을 것입니다 2>/dev/null
. 하지만 이 작업을 수행한 후에는 보시다시피 모든 변수에 대한 변수가 있습니다. 오래된 쉘 프로세스 - 내 플래그 포함 $var
.
두 번째 방법: 환경 변수
이 문제에 대해 Google을 한두 번 검색한 후 이것이 고려할 가치가 있는 또 다른 접근 방식이 될 수 있다고 생각했습니다. 처음에는 이렇게 생각했지만(분명히 틀렸어)단일 환경 변수의 값에 대해 커널 강제 임의 길이 제한이 있다는 믿음에 따라 이 옵션은 고려되지 않습니다.아그렌또는라이언 맥스 (이것이 영향을 미칠 수 있습니다)그러나 단일 값의 경우 더 작습니다. 그러나 내 올바른 진술은 다음과 같습니다.execve
전체 환경이 너무 크면 호출이 작동하지 않습니다. 따라서 이 접근 방식은 현재 환경이 호출을 허용할 만큼 충분히 작다는 것을 보장할 수 있는 경우에만 선호되어야 한다고 생각합니다 exec
.
사실, 다시 할 만큼 충분히 다릅니다.
ps -pF "$$"; : {1..10000000}; ps -pF "$$"
UID PID PPID C SZ RSS PSR STIME TTY TIME CMD
mikeserv 26296 4241 0 3957 3788 3 14:28 pts/1 00:00:00 bash -l
UID PID PPID C SZ RSS PSR STIME TTY TIME CMD
mikeserv 26296 4241 38 472722 1878740 3 14:28 pts/1 00:00:11 bash -l
첫 번째 라운드에서 제가 실패한 것 중 하나는 쉘 기능을 마이그레이션하는 것이었습니다. 직접 추적하는 것은 포함되지 않습니다.(아마도 이것이 가장 좋은 방법일 것이다), 내가 아는 한, 이 작업을 수행할 수 있는 쉘 이식 가능한 방법은 없습니다. bash
그러나 이는 함수가 이식 가능한 쉘 변수와 거의 동일한 방식으로 작동하기 때문에 실제로 허용됩니다 declare -f
. 첫 번째 방법을 사용하여 이를 수행하려면 set
여기 문서에 ; declare -f
추가 하면 됩니다.set
내 마커 변수는 동일하게 유지되지만 내 마커 기능은 다음과 같습니다.
chk () {
printf '###%s:###\n%s\n' \
\$VAR "${var-NOT SET}" \
PSINFO "$(ps -Fp $$)" \
ENV\ LEN "$(env | wc -c)"
}
따라서 새 셸에 파일 설명자를 제공하는 대신 이를 두 가지 환경 변수에 전달합니다.
varstate=$(set) fnstate=$(declare -f) exec "${0#-}" "-l$-"
좋아요 방금 실행 중인 쉘을 변경했습니다. 이제 어떻게 될까요?
chk
bash: chk: command not found
틀림없이. 하지만...
{ echo '###EVAL/UNSET $FNSTATE###'
eval "$fnstate"; unset fnstate
chk
echo '###EVAL/UNSET $VARSTATE###'
eval "$varstate"; unset varstate
chk
}
산출
###EVAL/UNSET $FNSTATE###
###$VAR:###
NOT SET
###PSINFO:###
UID PID PPID C SZ RSS PSR STIME TTY TIME CMD
mikeserv 26296 4241 10 3991 3736 1 14:28 pts/1 00:00:12 bash -lhimBH
###ENV LEN:###
6813
###EVAL/UNSET $VARSTATE###
bash: BASHOPTS: readonly variable
bash: BASH_VERSINFO: readonly variable
bash: EUID: readonly variable
bash: PPID: readonly variable
bash: SHELLOPTS: readonly variable
bash: UID: readonly variable
###$VAR:###
just
testing
'
this stuff
'
###PSINFO:###
UID PID PPID C SZ RSS PSR STIME TTY TIME CMD
mikeserv 26296 4241 10 4056 3772 1 14:28 pts/1 00:00:12 bash -lhimBH
###ENV LEN:###
2839
답변2
습관. Bash는 어떤 목적으로든 할당한 메모리를 운영 체제에 반환하지 않습니다. (근데 제가 틀렸다면 정정해주세요.)
그러나 bash는 필요한 경우 다른 목적으로 메모리를 재사용하고, 그렇지 않은 경우 커널은 메모리를 교체하여 실제로 RAM에 있지 않게 합니다.