개발자의 오르막

GoLang 의 포인터 본문

GoLang

GoLang 의 포인터

계단 2022. 7. 3. 11:35

포인터란?

  • 포인터는 메모리 주소를 값으로 갖는 타입을 의미
  • 변수의 주소 또한 메모리 주솟값 또는 숫자값이기 때문에 다른 변수의 값으로 사용될 수 있음
  • 메모리 주솟값을 변숫값을 가질 수 있는 변수를 포인터 변수라 함

참조 : Tucker 의 Go 언어프로그래밍

  • 메모리 주소를 값으로 가져 메모리 공간을 가리키는 타입을 포인터라 한다.
  • 포인터가 가리키는 값을 가져오는 것을 역참조라 한다.

 

 

포인터의 변수 선언

  • 포인터 변수는 가리키는 데이터 타입 앞에 *를 붙여서 선언
    • var p *int
    • p는 int 타입 데이터의 메모리 주소를 가리키는 포인터 변수
  • 포인터의 기본값은 nil
  • 포인터 사용예시
package main

import "fmt"

func pointer() {
	var a int = 500
	var p *int

	p = &a

	fmt.Printf("p의 값: %p\\n", p)
	fmt.Printf("p가 가리키는 메모리의 값: %d\\n", *p)
	*p = 100
	fmt.Printf("a의 값: %d\\n", a)
}

func main() {
	pointer()
}
  • 위처럼 a 의 변수에 값 500 을 갖고 있는 변수이며, p 는 a의 포인터 변수이다.
  • *p를 통해 역참조로, p가 가리키는 변수의 값을 출력한다.
  • *p = 100 으로 p가 가리키는 a 변수의 값을 변경할 수 있다.

 

포인터는 왜 써요?

  • 변수 대입이나 함수 인수 전달은 항상 값을 복사하기 때문에 많은 메모리 공간을 사용하는 문제와 큰 메모리 공간을 복사할 때 발생하는 성능 문제를 안고 있습니다.
  • 또한 다른 공간으로 복사되기 때문에 변경 사항이 적용되지도 않습니다.참조 : Tucker 의 Go 언어프로그래밍

참조 : Tucker 의 Go 언어프로그래밍

  • 그러나 포인터를 활용한 경우에는 이미 선언했던 변수의 메모리를 그대로 활용할 수 있으며, 역참조를 통해 해당 메모리에 저장된 변수 값을 활용할 수 있다.
  • 또한 그 메모리에 저장된 값을 변경할 수 있어, Micro 서비스를 구축할 때 메모리 활용을 포인터를 통해 극대화할 수 있다.

 

 

 

Pointer를 언제 써야 하나? : 값복사가 발생하여 메모리를 낭비하고 싶지 않을 때

  • AS-IS (변수에 값 대입 연산자를 사용)
package main

import "fmt"

type Data struct {
	value int
	data [200]int // 200개의 원소를 가진 int형 배열
}

func ChangeData(d Data) {
  // 새로운 변수 메모리에 값이 복사되고 있음 
	d.value = 999;
	d.data[100] = 999;
}

func main() {
	var data Data

	// 함수의 인자로 전달되면서 함수 스코프 내의 지역변수로 값 복사(메모리 사용)
	// struct의 크기는 201 * 8 바이트 만큼 할당됨.
	// 이 함수가 호출될 때마다 복사되어 메모리 낭비가 빈번히 일어남
	ChangeData(data) 

	fmt.Println(data.value)
	fmt.Println(data.data[100])
}
  • TO-BE (포인터를 활용)
// 포인터를 받아서 활용함. 포인터는 커봐야 8바이트임. 용량 절약 꿀!
func ChangeData(d *Data) {
  // 위에서 역참조로 가져온 값을 d 로 선언했기 때문에 역참조로 동작함
	d.value = 999;
	d.data[100] = 999;
}

func main() {
	var data Data

	// 변형할 데이터의 주소값을 넘김.
	// 포인터의 크기인 메모리 주소는 64비트 컴퓨터에선 8바이트, 32비트 컴퓨터에선 4바이트사용
	ChangeData(&data) 

	fmt.Println(data.value) // 999
	fmt.Println(data.data[100]) // 999
}
  • AS-IS 에서 ChangeData 를 호출할 때마다 값 복사가 일어나므로 메모리를 효율적으로 사용하지 못함
  • 포인터를 활용하게 되면, 포인터가 값복사가 되는데, 포인터는 8바이트밖에 안되서 메모리 효율이 좋음
Comments