29

.NET の文字列リテラルに関する最近の質問が私の目を引きました。同じ値を持つ異なる文字列が同じオブジェクトを参照するように、文字列リテラルがインターンされていることを知っています。また、実行時に文字列をインターンできることも知っています。

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

明らかに、実行時にインターンされる文字列はヒープに存在しますが、リテラルがプログラムのデータセグメントに配置されていると想定していました (上記の質問に対する私の回答でそう言いました)。しかし、私はこれをどこかで見た覚えがありません。これは私が行う方法であり、ldstrIL命令を使用してリテラルを取得し、割り当てが行われていないように見えるという事実が私を裏付けているように見えるので、これが当てはまると思います。

簡単に言うと、文字列リテラルはどこにあるのでしょうか? ヒープ上ですか、データ セグメントですか、それとも私が考えもしなかった場所ですか?


編集:文字列リテラルヒープに存在する場合、それらはいつ割り当てられますか?

4

7 に答える 7

109

.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 です。つまり、割り当てられたばかりです。誰がそれを応援していますか?

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()メソッドのスタックですが、 もあることに注意して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

出力を多少減らしましたが、お分かりいただけたでしょうか。

結論として、文字列はヒープ上にあります-インターンされている場合でも。内部テーブルは、ヒープ上のインスタンスへの参照を保持します。つまり、インターンされた文字列は、GC 中に収集されません。これは、インターンされたテーブルがそれらをルート化するためです。

于 2008-12-16T20:22:05.710 に答える
12

Javaの場合(Java用語集から):

SunのJVMでは、インターンされた文字列(文字列リテラルを含む)はperm genと呼ばれるRAMの特別なプールに格納され、JVMはクラスをロードしてネイティブにコンパイルされたコードも格納します。ただし、挿入された文字列は、通常のオブジェクトヒープに格納されていた場合と同じように動作します。

于 2008-12-16T20:38:19.843 に答える
3

間違っている場合は訂正してください。ただし、Java と .NET の両方で、すべてのオブジェクトがヒープ上に存在するわけではありませんか?

于 2008-12-16T20:21:27.850 に答える
1

.Net では、「インターン」された文字列リテラルは、「インターン テーブル」と呼ばれる特別なデータ構造に格納されます。これは、ヒープとスタックから分離されています。ただし、すべての文字列がインターンされているわけではありません...そうでないものはヒープに格納されていると確信しています。

ジャバを知らない

于 2008-12-16T20:23:21.620 に答える
1

ldstrIL命令に関するMSDNのサイトでこれを見つけました:

このldstr命令は、オブジェクト参照 (タイプ O) を、メタデータに格納されている特定の文字列リテラルを表す新しい文字列オブジェクトにプッシュします。このldstr命令は、必要な量のメモリを割り当て、文字列リテラルをファイルで使用されている形式から実行時に必要な文字列形式に変換するために必要な形式変換を実行します。

Common Language Infrastructure (CLI) は、同じ文字シーケンスを持つ 2 つのメタデータ トークンを参照する 2 つの ldstr 命令の結果が、正確に同じ文字列オブジェクトを返すことを保証します (「文字列インターニング」と呼ばれるプロセス)。

これは、文字列リテラルが実際には .NET のヒープに格納されていることを意味します ( mmyersで指摘されているJavaとは異なります)。

于 2008-12-17T07:08:04.037 に答える
0

Javaでは、すべてのオブジェクトのような文字列がヒープに存在します。ローカルプリミティブ変数(int、char、およびオブジェクトへの参照)のみがスタックに存在します。

于 2008-12-16T20:44:54.760 に答える
-1

Javaのインターン文字列は、文字列プールと呼ばれる別のプールにあります。このプールはStringクラスによって維持され、通常のヒープ(クラスデータの格納に使用される上記のPermプールではありません)に存在します。

私が理解しているように、すべての文字列がインターンされているわけではありませんが、myString.intern()を呼び出すと、文字列プールから保証された文字列が返されます。

参照: http : //www.javaranch.com/journal/200409/ScjpTipLine-StringsLiterally.htmlおよびjavadoc http://java.sun.com/j2se/1.5.0/docs/api/java/lang/String .html#intern()

于 2008-12-17T13:53:37.680 に答える