문제

최근 문자열 리터럴에 대한 질문 .NET에서 내 눈을 사로 잡았습니다. 나는 문자열 리터럴이 있다는 것을 알고 있습니다 인턴 따라서 동일한 값을 가진 다른 문자열은 동일한 객체를 나타냅니다. 또한 런타임에 문자열을 인턴 할 수 있다는 것을 알고 있습니다.

string now = DateTime.Now.ToString().Intern(); 

분명히 런타임에 인턴 된 문자열은 힙에 상주하지만 문자가 프로그램의 데이터 세그먼트에 배치되었다고 가정했습니다 ( 대답 질문에). 그러나 나는 어디서나 이것을 본 것을 기억하지 못한다. 나는 이것이 내가하는 방법과 사실이기 때문에 이것이 사실이라고 생각합니다. ldstr IL 명령은 리터럴을 얻는 데 사용되며 할당되지 않는 것 같습니다.

긴 이야기를 짧게 자르려면 문자열 리터럴은 어디에 있습니까? 힙, 데이터 세그먼트 또는 내가 생각하지 않은 곳에 있습니까?


편집하다: 문자열 리터럴 인 경우 하다 힙에 거주하면 언제 할당됩니까?

도움이 되었습니까?

해결책

.NET의 문자열은 참조 유형이므로 항상 힙에 있습니다 (인턴이있는 경우에도). WindBG와 같은 디버거를 사용하여이를 확인할 수 있습니다.

아래에 수업이있는 경우

   class SomeType {
      public void Foo() {
         string s = "hello world";
         Console.WriteLine(s);
         Console.WriteLine("press enter");
         Console.ReadLine();
      }
   }

그리고 당신은 전화합니다 Foo() 예를 들어, WindBG를 사용하여 힙을 검사 할 수 있습니다.

참조는 소규모 프로그램에 대한 레지스터에 저장 될 가능성이 높으므로 가장 쉬운 것은 특정 문자열에 대한 참조를 찾는 것입니다. !dso. 이것은 우리에게 해당 문자열의 주소를 제공합니다.

0:000> !dso
OS Thread Id: 0x1660 (0)
ESP/REG  Object   Name
002bf0a4 025d4bf8 Microsoft.Win32.SafeHandles.SafeFileHandle
002bf0b4 025d4bf8 Microsoft.Win32.SafeHandles.SafeFileHandle
002bf0e8 025d4e5c System.Byte[]
002bf0ec 025d4c0c System.IO.__ConsoleStream
002bf110 025d4c3c System.IO.StreamReader
002bf114 025d4c3c System.IO.StreamReader
002bf12c 025d5180 System.IO.TextReader+SyncTextReader
002bf130 025d4c3c System.IO.StreamReader
002bf140 025d5180 System.IO.TextReader+SyncTextReader
002bf14c 025d5180 System.IO.TextReader+SyncTextReader
002bf15c 025d2d04 System.String    hello world             // THIS IS THE ONE
002bf224 025d2ccc System.Object[]    (System.String[])
002bf3d0 025d2ccc System.Object[]    (System.String[])
002bf3f8 025d2ccc System.Object[]    (System.String[])

이제 사용하십시오 !gcgen 인스턴스가 어떤 생성인지 알아 보려면 다음과 같습니다.

0:000> !gcgen 025d2d04 
Gen 0

세대 제로에 있습니다. 즉, 할당되었습니다. 누가 응원하고 있습니까?

0:000> !gcroot 025d2d04 
Note: Roots found on stacks may be false positives. Run "!help gcroot" for
more info.
Scan Thread 0 OSTHread 1660
ESP:2bf15c:Root:025d2d04(System.String)
Scan Thread 2 OSTHread 16b4
DOMAIN(000E4840):HANDLE(Pinned):6513f4:Root:035d2020(System.Object[])->
025d2d04(System.String)

ESP는 우리의 스택입니다 Foo() 방법, 그러나 우리는 a object[] 또한. 그것이 인턴 테이블입니다. 한 번 보자.

0:000> !dumparray 035d2020
Name: System.Object[]
MethodTable: 006984c4
EEClass: 00698444
Size: 528(0x210) bytes
Array: Rank 1, Number of elements 128, Type CLASS
Element Methodtable: 00696d3c
[0] 025d1360
[1] 025d137c
[2] 025d139c
[3] 025d13b0
[4] 025d13d0
[5] 025d1400
[6] 025d1424
...
[36] 025d2d04  // THIS IS OUR STRING
...
[126] null
[127] null

출력을 다소 줄였습니다. 그러나 당신은 아이디어를 얻습니다.

결론적으로: 현은 인턴이 된 경우에도 힙에 있습니다. 인턴 테이블은 힙의 인스턴스에 대한 참조를 가지고 있습니다. IE 인턴 테이블이 뿌리를 내기 때문에 IE 인턴 된 현이 GC 중에 수집되지 않습니다.

다른 팁

Java (에서 자바 용어집):

Sun의 JVM에서 인턴 된 현 (문자 리터럴 포함)은 Perm Gen이라는 특수 RAM 풀에 저장되며 JVM은 클래스를로드하고 기본적으로 컴파일 된 코드를 저장합니다. 그러나, intered 문자열은 일반적인 물체 힙에 저장된 것과 다르게 행동하지 않습니다.

내가 틀렸다면 모든 객체가 자바와 .NET 모두에서 힙에 존재하지 않으면 나를 수정합니까?

.NET에서 "Interned"인 경우 문자열 리터럴은 "인턴 테이블"이라는 특수 데이터 구조에 저장됩니다. 이것은 힙과 스택과 분리되어 있습니다. 그러나 모든 문자열이 인턴되는 것은 아닙니다 ... 나는 힙에 저장되지 않은 것들을 확신합니다.

Java에 대해 모릅니다

나는 이것을 MSDN의 사이트에서 발견했다 ldstr IL 교육:

그만큼 ldstr 명령어 객체 참조 (O 형)을 메타 데이터에 저장된 특정 문자열 리터럴을 나타내는 새 문자열 객체로 푸시합니다. 그만큼 ldstr 지침 필요한 양의 메모리를 할당합니다 파일에 사용 된 양식에서 문자열 리터럴을 런타임에 필요한 문자열 형식으로 변환하는 데 필요한 형식 변환을 수행합니다.

CLI (Common Language Infrastructure)는 동일한 순서가 동일한 문자열 객체 ( "String Interning"으로 알려진 프로세스)를 정확하게 반환하는 두 개의 메타 데이터 토큰을 참조하는 두 개의 LDSTR 지침의 결과를 보장합니다.

이것은 문자열 리터럴이 실제로 .NET의 힙에 저장되어 있음을 의미합니다 (Java와 달리 지적했다 ~에 의해 마이어스).

Java에서는 모든 물체와 같은 문자열이 힙에 있습니다. 로컬 원시 변수 (int, char 및 객체에 대한 참조) 만 스택에 있습니다.

Java의 인턴 된 스트링은 문자열 풀이라는 별도의 수영장에 있습니다. 이 풀은 문자열 클래스에 의해 유지되며 일반 힙에 상주합니다 (위에서 언급 한 바와 같이 파마 수영장이 아닌 클래스 데이터를 저장하는 데 사용됩니다).

이해할 때 모든 문자열이 인턴되는 것은 아니지만 mystring.intern ()을 호출하면 문자열 풀에서 보장되는 문자열을 반환합니다.

또한보십시오:http://www.javaranch.com/journal/200409/scjptipline-stringsliterally.html그리고 Javadochttp://java.sun.com/j2se/1.5.0/docs/api/java/lang/string.html#intern ()

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top