티스토리 뷰

OS

Copy-on-Write (mmap)

tioon 2023. 5. 8. 19:42

 

 

프로세스 사이의 공유자원쓸때 문제점

프로세스가 fork()로 분기 되었을때의 상황입니다. 두개로 나뉨에 따라, 원래 프로세스가 가리키고 있던 메모리를 같이 가리키고 있습니다.  Table1 이 부모프로세스이고, Table2가 자식 프로세스입니다. 먼저 저번에는 한개의 process만 메모리를 건드리고 있었다면 지금은 새로운 process가 생겨 두개의 process가 동시에 실제 메모리를 가리키고 있는상황입니다.

 

  • READ상황
    -두 프로세스가 동시에 VP 1을 읽으려고 한다고 가정할때, 동시에 읽는건 가능합니다. 읽는건 실제 메모리를 건드리지않고 데이터만 가져오는 과정이기 때문에 실제메모리에 변화가 없기에 괜찮습니다.

  • WRITE상황 (실제메모리의 공유자원을 변경할때)
    -두 프로세스가 VP 1이라는 공유자원을 가지고 있을때 한 프로세스가 공유자원을 수정을 하게되면, 다른 프로세스입장에서도 공유자원이 바뀌기 때문에 이부분을 막기위해 복사과정이 일어나게됩니다.

 

Copy-on Write

-가상 메모리 기술 중 하나로 프로세스가 새로운 페이지를 복사할때 기존페이지를 공유하게 하고 필요한 경우에만 페이지를 복사하여 쓰는 방식입니다. 이는 메모리 사용량을 줄이는 효과가 있으며, fork()호출시 더욱 빠르게 수행할 수 있게 합니다.

맨위의 그림을 보시면 fork()로 프로세스가 만들어 졌을때 Table 1과 Table 2 는 같은 VP 1을 가리키고 있었습니다. 공유자원을 수정을 안하고 쓸때는 계속 그렇게 같은 공유자원을 가리키고 있지만, 공유자원의 수정(Write)이 일어나게될때에는 해당 공유자원을 새롭게 복사하여 만든후에  수정한 프로세스에서 그곳을 가리키는 방식으로 바뀌게 됩니다. 이런식으로 메모리자원을 절약할 수 있고 복사시에 속도도 빨라집니다.

 

 

mm_struct 

-가상 메모리를 구현할 수 있게하는 정보인데, 커널에서 각각의 가상메모리를 관리하기 위해 mm_struct라는 구조체에 정보를 저장해 각 프로세스의 가상 메모리를 추적하고 관리합니다. mm_struct의 구조는 다음과 같습니다.
fork()로 프로세스 복사시  이 정보도 같이 복사가 됩니다.

struct mm_struct {
	struct {
		struct vm_area_struct *mmap;		/* list of VMAs */
		struct rb_root mm_rb;
		
		/**
		 * @mm_users: The number of users including userspace.
		 *
		 * Use mmget()/mmget_not_zero()/mmput() to modify. When this
		 * drops to 0 (i.e. when the task exits and there are no other
		 * temporary reference holders), we also release a reference on
		 * @mm_count (which may then free the &struct mm_struct if
		 * @mm_count also drops to 0).
		 */
		atomic_t mm_users;

		/**
		 * @mm_count: The number of references to &struct mm_struct
		 * (@mm_users count as 1).
		 *
		 * Use mmgrab()/mmdrop() to modify. When this drops to 0, the
		 * &struct mm_struct is freed.
		 */
		atomic_t mm_count;

		unsigned long total_vm;	   /* Total pages mapped */
		unsigned long locked_vm;   /* Pages that have PG_mlocked set */
		atomic64_t    pinned_vm;   /* Refcount permanently increased */
		unsigned long data_vm;	   /* VM_WRITE & ~VM_SHARED & ~VM_STACK */
		unsigned long exec_vm;	   /* VM_EXEC & ~VM_WRITE & ~VM_STACK */
		unsigned long stack_vm;	   /* VM_STACK */
		unsigned long def_flags;

		spinlock_t arg_lock; /* protect the below fields */
		unsigned long start_code, end_code, start_data, end_data;
		unsigned long start_brk, brk, start_stack;
		unsigned long arg_start, arg_end, env_start, env_end;


	} __randomize_layout;

	/*
	 * The mm_cpumask needs to be at the end of mm_struct, because it
	 * is dynamically sized based on nr_cpu_ids.
	 */
	unsigned long cpu_bitmap[];
};

 

vm_area_struct

-mm_struct 내부에 있는 구조체로  mm_struct가 여러개를 가지고 있는 가상 메모리 영역의 정보를 담고 있는 구조체입니다.
fork()로 프로세스 복사시  이 정보도 같이 복사가 됩니다. 구조체의 정보는 다음과같습니다.

 

/*
 * This struct describes a virtual memory area. There is one of these
 * per VM-area/task. A VM area is any part of the process virtual memory
 * space that has a special rule for the page-fault handlers (ie a shared
 * library, the executable area etc).
 */
struct vm_area_struct {
	/* The first cache line has the info for VMA tree walking. */

	unsigned long vm_start;		/* Our start address within vm_mm. */
	unsigned long vm_end;		/* The first byte after our end address
					   within vm_mm. */

	/* linked list of VM areas per task, sorted by address */
	struct vm_area_struct *vm_next, *vm_prev;

	struct rb_node vm_rb;

	/*
	 * Largest free memory gap in bytes to the left of this VMA.
	 * Either between this VMA and vma->vm_prev, or between one of the
	 * VMAs below us in the VMA rbtree and its ->vm_prev. This helps
	 * get_unmapped_area find a free area of the right size.
	 */
	unsigned long rb_subtree_gap;

	/* Second cache line starts here. */

	struct mm_struct *vm_mm;	/* The address space we belong to. */

	/*
	 * Access permissions of this VMA.
	 * See vmf_insert_mixed_prot() for discussion.
	 */
	pgprot_t vm_page_prot;
	unsigned long vm_flags;		/* Flags, see mm.h. */

	/*
	 * For areas with an address space and backing store,
	 * linkage into the address_space->i_mmap interval tree.
	 */
	struct {
		struct rb_node rb;
		unsigned long rb_subtree_last;
	} shared;

	/*
	 * A file's MAP_PRIVATE vma can be in both i_mmap tree and anon_vma
	 * list, after a COW of one of the file pages.	A MAP_SHARED vma
	 * can only be in the i_mmap tree.  An anonymous MAP_PRIVATE, stack
	 * or brk vma (with NULL file) can only be in an anon_vma list.
	 */
	struct list_head anon_vma_chain; /* Serialized by mmap_sem &
					  * page_table_lock */
	struct anon_vma *anon_vma;	/* Serialized by page_table_lock */

	/* Function pointers to deal with this struct. */
	const struct vm_operations_struct *vm_ops;

	/* Information about our backing store: */
	unsigned long vm_pgoff;		/* Offset (within vm_file) in PAGE_SIZE
					   units */
	struct file * vm_file;		/* File we map to (can be NULL). */
	void * vm_private_data;		/* was vm_pte (shared mem) */

#ifdef CONFIG_SWAP
	atomic_long_t swap_readahead_info;
#endif
#ifndef CONFIG_MMU
	struct vm_region *vm_region;	/* NOMMU mapping region */
#endif
#ifdef CONFIG_NUMA
	struct mempolicy *vm_policy;	/* NUMA policy for the VMA */
#endif
	struct vm_userfaultfd_ctx vm_userfaultfd_ctx;
} __randomize_layout;

 

이 구조체들이 어떻게 쓰이냐 하면, 맨처음에 프로그램을 실행하게 되면 execve를 통해 vm_area_struct를 새롭게 만들고,

Create할때도 똑같이 vm_area_struct를 새로운지역에다 생성을 합니다. Free로 메모리 해제시 vm_area_struct가 삭제된다.

그림을 보시면 프로세스는 mm_struct를 한개씩만 가질 수 있습니다. 이 구조체에 vm_area_Struct 여러개가 저장이되어 프로세스에서 가지고 있는 가상메모리를 가지고 있으며, 이제 프로세스가 실행되면서 실제메모리로 올려야할때,  vm_area_struct를 참고하여 가상메모리를 실제 메모리로 올리게 됩니다.

mmap()

-리눅스에서 프로세스가 가상 주소 공간에 대해 메모리 매핑을 수행할 때 사용되는 시스템 호출 함수입니다. mmap 함수는 파일, 디바이스, 익명 메모리 등 다양한 소스에서 메모리 매핑을 지원합니다.

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
  • addr - 매핑될 가상 주소를 지정합니다.(NULL을 입력시 시스템이 자동으로 매핑함)
  • length - 매핑될 메모리 영역의 크기를 지정합니다.
  • prot - 메모리 영역에 적용할 보호모드(읽기,쓰기,실행 등)을 지정합니다.
  • flags - 메모리 매핑에 대한 옵션을 지정합니다. (MAP_PRIVATE, MAP_SHARED등이 있습니다.)
  • fd - 매핑될 파일의 파일 디스크립터를 지정합니다.
  • offset - 매핑될 파일의 오프셋을 지정합니다.

 

  mmap vs malloc 
  mmap malloc
종류 시스템 콜 인터페이스
할당크기 large memory 할당 small memory 할당
생성위치 stack과 heap 사이 heap

 

mmap의 장점
  • Lazy loading(지연로딩)
    -데이터나 자원을 필요할때만 그 부분만 로딩하는 방식입니다. 사용을하지않을땐 메모리에 매핑을하지않습니다. 이로 인해 메모리 사용량을 최소화 할 수 있습니다.
  • Memory management
    -munmap()이라는 함수로 해제를하게 될시 os로 빠르게 리턴해서 메모리 관리속도가 빨라진다.

 

 

 

[참고]

https://showx123.tistory.com/92

'OS' 카테고리의 다른 글

메모리 Stack변화  (0) 2023.05.15
Address Translation 변환 과정 (VA -> PA)  (0) 2023.05.15
가상 메모리(Virtual Memory)  (0) 2023.05.05
프로그램 -> 프로세스 변환과정 (컴파일)  (0) 2023.04.06
파일모드란?  (0) 2023.04.06
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
글 보관함