비교를 위한 소스
Main 메소드
.method private hidebysig static
void Main (
string[] args
) cil managed
{
// Method begins at RVA 0x2058
// Code size 27 (0x1b)
.maxstack 1
.entrypoint
.locals init (
[0] string
)
// string str = "Hello world!";
IL_0000: ldstr "Hello world!"
IL_0005: stloc.0
// Func(str);
IL_0006: ldloc.0
IL_0007: call void Program::Func(string)
// FuncRef(ref str);
IL_000c: ldloca.s 0
IL_000e: call void Program::FuncRef(string&)
// Console.ReadKey(true);
IL_0013: ldc.i4.1
IL_0014: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey(bool)
IL_0019: pop
// (no C# code)
IL_001a: ret
} // end of method Program::Main
여기서 ldloc.0은 0번 로컬변수를 스택에 넣는 명령어고 ldloca.s 0은 0번 로컬변수의 주소를 스택에 넣는 명령어
.method private hidebysig static
void Func (
string str
) cil managed
{
// Method begins at RVA 0x207f
// Code size 14 (0xe)
.maxstack 8
// Console.WriteLine(str);
IL_0000: ldarg.0
IL_0001: call void [mscorlib]System.Console::WriteLine(string)
// str = "";
IL_0006: ldstr ""
IL_000b: starg.s str
// (no C# code)
IL_000d: ret
} // end of method Program::Func
.method private hidebysig static
void FuncRef (
string& str
) cil managed
{
// Method begins at RVA 0x208e
// Code size 15 (0xf)
.maxstack 8
// Console.WriteLine(str);
IL_0000: ldarg.0
IL_0001: ldind.ref
IL_0002: call void [mscorlib]System.Console::WriteLine(string)
// str = "";
IL_0007: ldarg.0
IL_0008: ldstr ""
IL_000d: stind.ref
// (no C# code)
IL_000e: ret
} // end of method Program::FuncRef
Func이랑 FuncRef의 함수 본문을보면 같은 동작인데도 명령어가 더 늘었지? 그럼 뭐가 더 빠를까
내가 올린 예제랑 상황이 다르자나 완전. string은 참조타입이지만 변수로 다룰때 값처럼 다뤄지게 재정의 되있는거아님? 내가 올린 예제 다시한번 잘봐봐 이거랑 다른 상황같아
니가 디컴파일해서 봐봐 원래 참조타입은 스택에서 포인터라서 값처럼 다룸
값타입은 명령어가 또 다르다
ref를 쓰기위해 명령문이 늘어났다고 메모리공간에 주소값 변수가 하나 더 복사되는거보다 느리다고? 책이 잘못됫다는건지 먼지 이해가 안되네
니가 스택이랑 힙 구조를 잘 모르는것같다
메모리 사용은 어차피 객체는 하나니까 똑같고 ref쓰면 부수적인 작업이 더 필요해서 속도는 더 느리다는거임
값타입은 복사비용이 포인터보다 커질수 있으니 얘는 케바케
그니까 니 말은 내예제에서 첫번째 상황은 스택공간에 a 힙주소값을 복사한 a1이 하나더 만들어지는건 맞는데 두번째 상황은 바로 주소값을 가르킨다하더라도 ref를 사용하기위한 내부작동명령때문에 두번째 상황이 더 느릴것이다라는거임?
객체는 하나맞는데 그 객체를 가르키는 스택변수가 두개가 된다니까? 첫번째 상황은
스택에 변수 생기는건 똑같음 둘다 포인터 매개변수 하나씩 달고있잖아 그리고 주소를 바로 가리키는건 첫번째다
바로 안가리키니까 그거 찾는다고 두번째가 명령어가 많지
책에선 두번째 상황은 a변수의 스택 주소값이 직접 전달되는거고 첫번째 상황은 참조값이 또다른 공간에 복사되어 전달된다고 나옴(얕은복사). 그럼 두번째는 스택에 변수생기는게 아닌데 왜자꾸 둘다 변수생긴다는거야. 책이 잘못된거야 머야 혼란스럽게
두 예제 꼼꼼하게 본거 맞지?
두번째는 스택의 주소값이 복사되는거고 첫번째는 객체의 주소값이 복사되는거
그 스택의 주소에 객체의 주소가 들어있으니 두번째는 주소찾는걸 두번해야하는거지
책에서는 추상적으로 말한거같은데 실제 동작은 두번째가 더 복잡함
첫번째가 객체의 주소값을 복사하려면 어쨋든 a 에서 주소값을 확인할테고 그 확인한걸 a1에 새롭게 복사하고 찾아들어가니 두번하는건 마찬가지아닌가. 두번째는 a에서 주소값을 보러 들어간건 맞는데 찾는건 a가 알아서 네비찍어놧으니 a엉덩이에만 붙어있음 알아서 같이 도달하는거고. 이래나 저래나 마찬가지아님? 어쨋든 니말은 책의 내용이 맞긴한데 사실은 두번째엔 숨은동작들이 더있어서 두번째가 더 복잡한 명령이다라는거지?
그냥 그렇게 대강 알고 나중에 다시봐라 아니면 C같은걸 배워보던가
걍 c#하나만 팔래. 어차피 구현만하면 되는거니 내부작동까지 세세히 알필요있나. 난 그냥 둘중 뭐가더 효율적인가가 궁금했을뿐임. 어쨋든 성의있는 답변 고맙다. 프갤에서 젤 친절하네