C#에서 String이 값 유형처럼 동작하는 참조 유형인 이유는 무엇입니까?
문자열은 동일한 개체를 참조하는 대신 텍스트를 비교하기 위해 ==가 오버로드되는 등 값 유형의 특성을 대부분 가지고 있지만 참조 유형입니다.
그럼 문자열은 왜 단순한 값 유형이 아닐까요?
문자열은 크기가 클 수 있고 힙에 저장해야 하므로 값 유형이 아닙니다.값 타입은 스택에 저장되어 있습니다(CLR의 모든 실장에서는 아직).스택을 할당하면 모든 것이 중단됩니다.스택은 32비트의 경우 1MB, 64비트의 경우 4MB에 불과합니다.각 스트링을 박스화해야 합니다.복사 패널티가 발생합니다.스트링을 삽입할 수 없습니다.메모리 사용량이 급증합니다.
(편집: 구현 세부 사항인 가치 유형 스토리지에 대한 설명 추가. 이로 인해 가치 기호가 시스템에서 상속되지 않는 유형이 있습니다.Value Type(밸류 타입)감사합니다.Ben )
값 유형인 경우 성능(공간 및 시간!)이 형편없고 메서드에서 전달 및 반환될 때마다 해당 값을 복사해야 하므로 값 유형이 아닙니다.
그것은 세상을 온전하게 유지하기 위한 가치관을 가지고 있다.코드화하기가 얼마나 어려울지 상상이 가십니까?
string s = "hello";
string t = "hello";
bool b = (s == t);
설정하다b
false
어떤 어플리케이션에서도 코딩이 얼마나 어려운지 상상해 보세요.
문자열은 값 의미론을 가진 참조 유형입니다.이 설계는 특정 성능 최적화를 가능하게 하는 트레이드오프입니다.
참조 유형과 값 유형의 구별은 기본적으로 언어 설계의 성능 트레이드오프입니다.참조 유형은 힙에 생성되기 때문에 구축 및 파괴 및 가비지 수집에 대한 오버헤드가 있습니다.반면 값 유형은 개체 전체가 포인터가 아닌 메모리에 복사되기 때문에 할당 및 메서드 호출에 오버헤드가 발생합니다(데이터 크기가 포인터보다 큰 경우).문자열은 포인터의 크기보다 훨씬 클 수 있기 때문에(일반적으로 크기도 합니다) 참조 유형으로 설계되어 있습니다.게다가 값 타입의 사이즈는 컴파일시에 알 필요가 있습니다.이것은 문자열의 경우는 항상 그렇지만은 않습니다.
그러나 문자열은 불변하며 참조를 비교하는 것이 아니라 값(즉, 문자열의 경우 문자별)에 의해 비교되는 값 의미론을 가집니다.이를 통해 다음과 같은 특정 최적화가 가능합니다.
인터닝이란 여러 문자열이 동일한 것으로 알려진 경우 컴파일러는 하나의 문자열만 사용할 수 있으므로 메모리를 절약할 수 있다는 것을 의미합니다.이 최적화는 스트링이 불변인 경우에만 기능합니다.그렇지 않으면 1개의 스트링을 변경하면 다른 스트링에서 예측할 수 없는 결과가 됩니다.
문자열 리터럴(컴파일 시에 알려진)은 컴파일러에 의해 메모리의 특별한 정적 영역에 삽입하여 저장할 수 있습니다.이렇게 하면 할당 및 가비지 수집이 필요하지 않으므로 런타임에 시간이 절약됩니다.
불변의 문자열은 특정 작업의 비용을 증가시킵니다.예를 들어, 단일 문자를 일괄적으로 바꿀 수 없습니다. 변경에 대해 새 문자열을 할당해야 합니다.그러나 이는 최적화의 이점에 비하면 적은 비용입니다.
값 의미론은 사용자에 대한 참조 유형과 값 유형 간의 차이를 효과적으로 숨깁니다.유형에 값 의미론이 있는 경우, 유형이 값 유형인지 참조 유형인지는 중요하지 않습니다. 구현 세부 사항으로 간주할 수 있습니다.
이것은 오래된 질문에 대한 늦은 답변이지만, 다른 모든 답변은 요점을 놓치고 있습니다.그것은 그것입니다.까지는 NET에 제네릭이 없었습니다.2005년의 NET 2.0.
String
는 값 타입이 아닌 참조 타입입니다.이는 Microsoft가 일반적이지 않은 컬렉션에서 문자열을 가장 효율적으로 저장할 수 있도록 하는 것이 매우 중요했기 때문입니다.System.Collections.ArrayList
.
을 일반적이지 에 저장하려면 , 「」의합니다.object
값 하면 CLR 내부로 이 랩됩니다.System.Object
이치노
컬렉션에서 값을 읽으려면 역연산이 필요하며 이를 언박싱이라고 합니다.
박스와 언박스는 둘 다 무시할 수 없는 비용이 듭니다.박스는 추가 할당이 필요하고 언박스는 타입 체크가 필요합니다.
, 틀리다, 틀린 , 라고 하는 대답도 있습니다.string
는 크기가 가변적이기 때문에 값 유형으로 구현할 수 없습니다.실제로 문자열의 길이를 나타내는 정수와 char 배열에 대한 포인터의 두 개의 필드를 포함하는 고정 길이의 데이터 구조로서 문자열을 구현하는 것은 쉽습니다.게다가 스몰 스트링 최적화 전략도 사용할 수 있습니다.
제네릭이 첫날부터 존재했다면 의미론도 단순하고 메모리 사용률도 높으며 캐시 인접성이 뛰어난 스트링을 값 유형으로 하는 것이 더 나은 해결책이었을 것입니다. a.List<string>
작은 문자열만 포함하는 것은 하나의 연속된 메모리 블록일 수 있습니다.
문자열만 불변의 참조 유형인 것은 아닙니다.멀티 캐스트 대표님들도.그렇기 때문에 글을 쓰는 것이 안전합니다.
protected void OnMyEventHandler()
{
delegate handler = this.MyEventHandler;
if (null != handler)
{
handler(this, new EventArgs());
}
}
스트링과 함께 작업하고 메모리를 할당하는 가장 안전한 방법이기 때문에 스트링은 불변이라고 생각합니다.왜 Value 타입이유스택 사이즈 등에 대해서는 이전 저자의 의견이 옳습니다.또한 프로그램에서 동일한 상수 문자열을 사용할 경우 문자열을 참조 유형으로 만들면 어셈블리 크기를 절약할 수 있습니다.정의하면
string s1 = "my string";
//some code here
string s2 = "my string";
"my string" 상수의 두 인스턴스가 어셈블리에 한 번만 할당될 수 있습니다.
통상적인 참조 타입과 같이 스트링을 관리하는 경우는, 새로운 String Builder(string s)내에 스트링을 넣습니다.또는 MemoryStreams를 사용합니다.
함수에서 대량의 문자열이 전달될 것으로 예상되는 라이브러리를 작성하려면 파라미터를 StringBuilder 또는 Stream으로 정의합니다.
매우 간단한 말로, 크기가 일정한 값은 값 유형으로 취급할 수 있습니다.
또,(단마다 할 때, 현의 구현 방식(단마다 다르다)이.를 들어 "a"를 합니다.StringBuilder
큰 메모리를 합니다.버퍼에 복사하기 위한 버퍼를 할당하고, 마지막에 도달하면 큰 연결 퍼포먼스를 방해받지 않기 위해 더 많은 메모리를 할당합니다.
존 스키트가 도와줄까?
주로 퍼포먼스 문제입니다.
문자열이 LIKE 값 유형처럼 동작하는 것은 코드를 작성할 때 도움이 되지만 BE 값 유형이 있으면 성능이 크게 저하됩니다.
자세한 내용은 .net 프레임워크의 문자열에 관한 훌륭한 기사를 참조하십시오.
알 수 요?string
조유 ??나는 그것이 어떻게 구현되는지가 중요한지 잘 모르겠다.C#의 문자열은 정확하게 불변하기 때문에 이 문제에 대해 걱정할 필요가 없습니다.
실제로 문자열은 값 유형과 거의 유사하지 않습니다.우선 모든 값 유형이 불변하는 것은 아닙니다.Int32 값은 원하는 대로 변경할 수 있으며 스택 상의 주소는 동일합니다.
문자열은 매우 타당한 이유로 불변합니다. 문자열이 참조 유형인 것과는 무관하지만 메모리 관리와 많은 관련이 있습니다.문자열 크기가 변경되었을 때 새 개체를 생성하는 것이 관리 힙에서 항목을 이동하는 것보다 더 효율적입니다.가치/참조 유형과 불변의 객체 개념을 혼합하고 있는 것 같습니다.
"=="까지: 말씀하신 대로 "=="는 연산자 오버로드이며, 문자열 작업 시 프레임워크를 더욱 유용하게 만들기 위해 구현되었습니다.
많은 사람들이 값 유형 및 원시 유형과 관련하여 스택과 메모리를 언급하는 것은 마이크로프로세서의 레지스터에 적합해야 하기 때문입니다.레지스터보다 더 많은 비트가 소요될 경우 스택에서 무언가를 푸시하거나 팝할 수 없습니다.명령어는 예를 들어 "pop eax"입니다. 32비트 시스템에서는 eax가 32비트 너비이기 때문입니다.
부동소수점 프리미티브타입은 폭 80비트인 FPU에 의해 처리됩니다.
이것은 모두 OOP 언어가 존재하기 훨씬 전에 결정되어 원시 유형의 정의를 난독화시켰으며, 값 유형은 OOP 언어 전용으로 만들어진 용어라고 생각합니다.
문자열이 문자 배열로 구성된 것처럼 단순하지 않습니다.문자열은 문자 배열로 간주됩니다.따라서 참조 메모리 위치가 스택에 저장되고 힙에 있는 어레이 메모리 위치의 시작을 가리키기 때문에 힙에 있습니다.문자열 크기를 할당하기 전에 알 수 없습니다. 힙에 대해 완벽합니다.
그렇기 때문에 같은 크기의 문자열이라도 변경할 경우 컴파일러는 이를 인식하지 못하고 새 배열을 할당하고 배열 위치에 문자를 할당해야 하기 때문에 문자열은 불변합니다.문자열은 언어를 통해 메모리를 즉시 할당하지 않아도 된다고 생각하면 의미가 있습니다(프로그래밍과 같이 C를 읽습니다).
언급URL : https://stackoverflow.com/questions/636932/in-c-why-is-string-a-reference-type-that-behaves-like-a-value-type
'source' 카테고리의 다른 글
ObjectDataProvider를 통해 ComboBox를 일반 사전에 바인딩하는 방법 (0) | 2023.04.26 |
---|---|
WPF에서의 이미지 동적 로드 (0) | 2023.04.21 |
URIFormatException: 잘못된 URI: 잘못된 포트가 지정됨 (0) | 2023.04.21 |
Windows Azure 서비스를 빌드할 때 경로가 너무 깁니다. (0) | 2023.04.21 |
C++에서 int를 문자열로 변환하는 가장 쉬운 방법 (0) | 2023.04.21 |