Linux의 메모리 사용

devops의 세계에서 많은 도구들이 우리가 Datadogs,Grafana 등 지표를 사용하여 메모리 사용 상황을 감시하는 것을 지원한다. 그러나 전통적인 사람들은 여전히 수동으로 메모리 소모를 감시하는 지식과 기능을 습득하도록 요구한다.
  • 본고는 리눅스에서 프로세스의 메모리 소모를 측정하는 합리적인 방법을 소개했다.Linux는 가상 메모리 관리를 갖추고 있기 때문에 단일 프로세스의 메모리 소모를 측정하는 것은 대부분의 사용자들이 생각하는 것처럼 간단하지 않다.본고는 메모리 소모와 관련된 모든 지표에서 어떤 정보를 얻을 수 있는지 설명한다.
  • 가장 많이 사용되는 Linux 도구는 VSZ(가상 메모리 크기) 및 RSS(주류 세트 크기), 새 도구는 PSS(비례 세트 크기)

  • 이 서류 안에 무엇이 있느냐
  • Technical Terms
  • VSZ (Virtual Memory Size) and Demand Paging
  • RSS (Resident Set Size) and Shared Libraries
  • PSS (Proportional Set Size)
  • Python script to get PSS (Proportional Set Size)

  • 🚀 기술 용어
    1. 페이지
  • Linux에서 메모리 관리를 위한 메모리 블록입니다.일반적인 Linux 시스템에서는 한 페이지가 4096바이트입니다.
  • 2. 물리적 기억
  • 이것은 컴퓨터의 실제 메모리로 통상적으로 RAM이다.
  • 3. 가상 메모리
  • 이것은 프로세스에 주어진 메모리 공간으로 프로세스가 컴퓨터의 실제 메모리량이나 다른 프로세스의 메모리 소모 상황을 막론하고 다른 프로세스와 분리된 연속 메모리를 가지고 있다고 생각하게 한다.가상 메모리 페이지는 물리 메모리 페이지에 비추기 때문에 프로세스는 가상 메모리만 고려할 수 있다.

  • 🚀 VSZ(가상 메모리 크기) 및 주문형 페이지
  • 프로세스의 메모리 소모량을 측정하기 위해 VSZ(가상 메모리 크기)를 사용하는 것을 고려하는 것은 큰 의미가 없다.페이지 나누기를 요청하는 기능으로 불필요한 메모리 소모를 억제할 수 있기 때문이다.
  • 예를 들어 emacs라는 텍스트 편집기는 XML 파일을 처리할 수 있는 함수를 가지고 있다.그러나 이런 기능들은 계속 사용되고 있는 것은 아니다.사용자가 순수한 텍스트만 편집하고 싶을 때, 이 함수들을 물리 메모리에 불러올 필요가 없다.요청 페이지 나누기 기능은 프로세스가 이 페이지를 사용하지 않는 한 페이지를 불러오지 않습니다.
  • 이것이 바로 그의 작업 원리다.우선, 프로그램이 시작될 때, 리눅스는 프로세스에 가상 메모리 공간을 제공하지만, 실제로는 함수가 있는 페이지를 물리 메모리에 불러오지 않는다.프로그램이 가상 메모리의 함수를 실제로 호출할 때, CPU의 MMU는 리눅스 페이지가 불러오지 않았음을 알려 줍니다.그런 다음 Linux는 프로세스를 일시 중지하고 페이지를 물리적 메모리로 로드한 다음 프로세스의 가상 메모리에 페이지를 매핑한 다음 프로세스를 일시 중지된 위치에서 다시 실행합니다.따라서 프로세스가 중단되었다는 것을 알 필요가 없다. 함수가 가상 메모리에 불러왔다고 간단하게 가정하고 사용하면 된다.
  • VSZ(가상 메모리 크기)는 페이지가 실제 메모리에 로드되었는지 여부에 관계없이 프로세스의 전체 가상 메모리 크기를 설명합니다.따라서 이것은 메모리 소모를 평가하는 실제 지표가 아니다. 왜냐하면 실제 소모되지 않은 페이지를 포함하기 때문이다.

  • 🚀 RSS(상주 세트 크기) 및 공유 라이브러리
  • RSS(상주 세트 크기)는 실제 물리적 메모리에 로드된 프로세스의 전체 페이지 수를 설명합니다.이것은 프로세스가 소모하는 실제 메모리량처럼 VSZ(가상 메모리 크기)보다 좋지만 공유 라이브러리나 동적 링크 라이브러리라고 불리는 기능 때문에 그리 간단하지 않다.
  • 라이브러리는 프로그램이 특정 기능을 처리할 수 있는 모듈이다.예를 들어, libpng입니다.따라서 PNG 이미지 파일의 압축과 압축을 담당하고libxml2를 압축합니다.XML 파일을 처리해야 합니다.그들은 모든 프로그래머에게 이 함수를 작성하게 하지 않고 다른 사람이 개발한 라이브러리로 그들이 원하는 결과를 실현할 수 있다.
  • 공유 대상은 여러 프로그램이나 프로세스가 공유할 수 있는 라이브러리입니다.예를 들어 두 개의 프로세스가 동시에 실행된다고 가정하면 공유 라이브러리libxml2의 XML 처리 함수를 사용하기를 원합니다.그래서Linux는 더 이상 똑같은 기능을 가진 페이지를 여러 번 불러오지 않고 물리적 메모리에 한 번 불러오고 두 프로세스의 가상 메모리에 비추어 줍니다.이 두 프로세스는 이 함수를 다른 사람과 공유할지 여부에 대해 신경 쓸 필요가 없다. 왜냐하면 이 함수에 접근해서 자신의 가상 메모리에서 사용할 수 있기 때문이다.이 특성 때문에 리눅스는 불필요한 메모리 페이지 복사를 억제했다.
  • 이제 위의 같은 예로 돌아갑시다.텍스트 편집기 Emacs에는 XML 파일을 처리하는 기능이 있습니다.이것은 공유 라이브러리libxml2가 책임집니다.그래서이번에emacs를 실행하는 사용자는 실제적으로 XML 파일을 처리하고 있으며,emacs는libxml2의 함수를 사용하고 있습니다.그래서또한 백엔드에서 실행되는 두 개의 프로세스가libxml2를 사용하고 있습니다.저도요.libxml2부터 시작합니다.공유 라이브러리도 마찬가지다. 리눅스는 물리적 메모리에 한 번만 불러와 세 프로세스의 가상 메모리에 비추는다.
  • emacs의 RSS (상주 집합 크기) 를 보았을 때libxml2 페이지를 포함합니다.그래서이것은emacs가 실제로 그것을 사용하고 있기 때문에 틀린 것이 아닙니다.그런데 다른 두 과정은요?이러한 기능을 사용하는 것은emacs만이 아니다.모든 세 프로세스의 RSS (상주 집합 크기) 를 더하면libxml2입니다.물리적 메모리에 한 번만 불러와도 세 번 계산될 것이다.
  • 따라서
  • RSS(상주 집합 크기)는 프로세스가 스스로 실행될 때 메모리 소모량을 표시하고 다른 프로세스와 어떤 내용도 공유하지 않는다는 지시기이다.공유 라이브러리의 실제 상황에 대해 RSS(상주 집합 크기)는 프로세스가 소모하는 메모리의 양을 높게 평가한다.도량 프로세스를 사용하는 메모리 소모는 틀리지 않았지만, 이 행동을 기억해야 할 수도 있습니다.

  • 🚀 PSS(배율 설정 크기)
  • PSS(배율 설정 크기)는 개별 프로세스의 메모리 사용량을 측정하는 데 사용되는 비교적 새로운 표시기입니다.그것은 아직 모든 리눅스 시스템에서 사용할 수 없지만, 사용할 수 있다면 쓸모가 있을 것이다.공유 페이지를 사용하는 프로세스 간에 공유 페이지의 메모리를 평균적으로 분배하는 개념이다.
  • PSS(비례에 따라 크기를 설정)는 메모리 소모를 이렇게 계산한다. 만약에 N개의 프로세스가 공유 라이브러리를 사용하고 있다면 모든 프로세스가 공유 라이브러리 페이지의 N분의 1을 소모한다.
  • 위의 예에서emacs는 다른 두 프로세스와libxml2의 페이지를 공유한다.그래서세 개의 프로세스가 있기 때문에 PSS는 프로세스마다 3분의 1의libxml2를 소모하는 것을 고려할 것이다.몇 페이지 더 있어요.
  • 는 RSS(상주 집합 크기)보다 PSS(비례 집합 크기)가 더 현실적인 지표라고 생각한다.특히 시스템 전체의 메모리 소모를 함께 고려하고 싶을 때, 프로세스마다 단독으로 고려하지 않을 때, 그 효과가 더욱 좋다.예를 들어 여러 개의 프로세스와 수호 프로세스를 가진 시스템을 개발하고 장치에 얼마나 많은 메모리를 설치해야 할지 추측하고 싶을 때 PSS (비례 설정 크기) 는 RSS (상주 설정 크기) 보다 더 잘 작동한다.

  • 🚀 PSS에 대한 Python 스크립트 가져오기
    https://github.com/vumdao/pss-memory-get/blob/master/pss.py
    #! /usr/bin/env python3
    # coding: utf-8
    ##-----------------------------------------------------------------------------
    ## pss.py --- Print the PSS (Proportional Set Size) of accessable processes
    ##-----------------------------------------------------------------------------
    import os, sys, re, pwd
    from functools import cmp_to_key as cmp
    
    
    ##-----------------------------------------------------------------------------
    def pss_main():
        '''
        Print the user name, pid, pss, and the command line for all accessable
        processes in pss descending order.
        '''
        # Get the user name, pid, pss, and the command line information for all
        # processes that are accessable. Ignore processes where the permission is
        # denied.
        ls = []   # [(user, pid, pss, cmd)]
        for pid in filter(lambda x: x.isdigit(), os.listdir('/proc')):
            try:
                ls.append((owner_of_process(pid), pid, pss_of_process(pid), cmdline_of_process(pid)))
            except IOError:
                pass
    
        # Calculate the max length of the user name, pid, and pss in order to
        # print them in aligned columns.
        userlen = 0
        pidlen = 0
        psslen = 0
        for (user, pid, pss, cmd) in ls:
            userlen = max(userlen, len(user))
            pidlen = max(pidlen, len(pid))
            psslen = max(psslen, len(str(pss)))
    
        # Get the width of the terminal.
        with os.popen('tput cols') as fp:
            term_width = int(fp.read().strip())
    
        # Print the information. Ignore kernel modules since they allocate memory
        # from the kernel land, not the user land, and PSS is the memory
        # consumption of processes in user land.
        fmt = '%%-%ds  %%%ds  %%%ds  %%s' % (userlen, pidlen, psslen)
        print(fmt % ('USER', 'PID', 'PSS', 'COMMAND'))
        for (user, pid, pss, cmd) in sorted(ls, key=cmp(lambda x, y: (y[2] - x[2]))):
            if cmd != '':
                print((fmt % (user, pid, pss, cmd))[:term_width - 1])
    
    
    ##-----------------------------------------------------------------------------
    def pss_of_process(pid):
        '''
        Return the PSS of the process specified by pid in KiB (1024 bytes unit)
    
        @param pid  process ID
        @return     PSS value
        '''
        with open('/proc/%s/smaps' % pid) as fp:
            return sum([int(x) for x in re.findall('^Pss:\s+(\d+)', fp.read(), re.M)])
    
    
    ##-----------------------------------------------------------------------------
    def cmdline_of_process(pid):
        '''
        Return the command line of the process specified by pid.
    
        @param pid  process ID
        @return     command line
        '''
        with open('/proc/%s/cmdline' % pid) as fp:
            return fp.read().replace('\0', ' ').strip()
    
    
    ##-----------------------------------------------------------------------------
    def owner_of_process(pid):
        '''
        Return the owner of the process specified by pid.
    
        @param pid  process ID
        @return     owner
        '''
        try:
            owner_pid = pwd.getpwuid(os.stat('/proc/%s' % pid).st_uid).pw_name
        except Exception:
            return 'docker'
        return owner_pid
    
    
    ##-----------------------------------------------------------------------------
    if __name__ == '__main__':
        pss_main()
    
  • 어떻게 달리기sudo python pss.py
  • 서버/실례가 실행 중docker일 경우userID999ref
  • Refs
    ·
    Github
    ·
    Web
    ·
    ·
    ·
    Page
    ·

    좋은 웹페이지 즐겨찾기