Jenis array, tumpukan, tumpukan, dan nilai

 int[] myIntegers; myIntegers = new int[100]; 

Dalam kode di atas, apakah ada int baru [100] yang menghasilkan array di heap? Dari apa yang saya baca di CLR hingga C #, jawabannya adalah ya. Tapi saya tidak bisa mengerti apa yang terjadi dengan int sebenarnya di dalam array. Karena mereka adalah tipe nilai, saya akan menyarankan bahwa mereka perlu dimasukkan ke dalam kotak, jadi bagaimana saya bisa, misalnya, mengirimkan myIntegers ke bagian lain dari program, dan itu mengacaukan tumpukan jika mereka tetap di atasnya sepanjang waktu, Atau saya salah? Saya berasumsi bahwa mereka hanya akan ditempatkan di dalam kotak dan akan hidup di heap selama array ada.

117
11 июля '09 в 17:30 2009-07-11 17:30 elysium melahap diatur 11 Juli 2009 pada 17:30 2009-07-11 17:30
@ 8 jawaban

Array Anda menonjol di tumpukan, dan int tidak sesuai di dalam kotak.

Sumber kebingungan Anda mungkin karena orang mengatakan bahwa tipe referensi dialokasikan pada heap, dan tipe nilai dialokasikan pada stack. Ini bukan representasi yang akurat.

Semua variabel dan parameter lokal didistribusikan di tumpukan. Ini termasuk tipe nilai dan tipe referensi. Perbedaan di antara mereka hanyalah apa yang disimpan dalam variabel. Tidak mengherankan bahwa untuk tipe nilai, nilai tipe disimpan >

Hal yang sama berlaku untuk bidang. Ketika memori dialokasikan untuk instance dari tipe agregat (kelas atau struktur), itu harus berisi penyimpanan untuk masing-masing bidang instance. Untuk bidang tipe referensi, repositori ini hanya berisi referensi ke nilai, yang nantinya akan dialokasikan pada heap. Untuk bidang tipe nilai, toko ini berisi nilai aktual.

Jadi, diberikan jenis berikut:

 class RefType{ public int I; public string S; public long L; } struct ValType{ public int I; public string S; public long L; } 

Nilai dari masing-masing jenis ini akan membutuhkan 16 byte memori (dengan asumsi ukuran kata 32-bit). Bidang I dalam setiap kasus membutuhkan 4 byte untuk menyimpan nilainya, bidang S membutuhkan 4 byte untuk menyimpan referensi, dan bidang L membutuhkan 8 byte untuk menyimpan nilainya. Dengan demikian, memori untuk nilai RefType dan ValType sebagai berikut:

  0 ───────────────────┐│ I │  4 ├──────────────────┤│ S │  8 ├──────────────────┤│ L ││ │ 16 └──────────────────┘

Sekarang, jika Anda memiliki tiga variabel lokal dalam fungsi, ketik RefType , ValType dan int[] , misalnya:

 RefType refType; ValType valType; int[] intArray; 

maka tumpukan Anda mungkin terlihat seperti ini:

  0 ───────────────────┐│ refType │  4 ├──────────────────┤│ valType ││ ││ ││ │ 20 ├──────────────────┤│ intArray │ 24 └──────────────────┘

Jika Anda menetapkan nilai ke variabel lokal ini, misalnya:

 refType = new RefType(); refType.I = 100; refType.S = "refType.S"; refType.L = 0x0123456789ABCDEF; valType = new ValType(); valType.I = 200; valType.S = "valType.S"; valType.L = 0x0011223344556677; intArray = new int[4]; intArray[0] = 300; intArray[1] = 301; intArray[2] = 302; intArray[3] = 303; 

Maka tumpukan Anda mungkin terlihat seperti ini:

  0 ───────────────────┐│ 0x4A963B68 - heap address dari `refType`  4 ├──────────────────┤│ 200 │ - nilai `valType.I`│ 0x4A984C10 - heap address dari `valType.S`│ 0x44556677 - `valType.L` 32-bit yang rendah│ 0x00112233 │ - `valType.L` 32-bit yang tinggi 20 ├──────────────────┤│ 0x4AA4C288 - heap address dari `intArray` 24 └──────────────────┘

Memori pada 0x4A963B68 (nilai RefType) akan terlihat seperti ini:

  0 ───────────────────┐│ 100 │ - nilai `refType.I`  4 ├──────────────────┤│ 0x4A984D88 - heap address dari `refType.S`  8 ├──────────────────┤│ 0x89ABCDEF │ - `refType.L` 32-bit yang rendah│ 0x01234567 │ - `refType.L` 32-bit yang tinggi 16 └──────────────────┘

Memori pada 0x4AA4C288 (nilai intArray) akan terlihat seperti ini:

  0 ───────────────────┐│ 4 │ - panjang array  4 ├──────────────────┤│ 300 │ - `intArray [0]`  8 ├──────────────────┤│ 301 │ - `intArray [1]` 12 ───────────────────┤│ 302 │ - `intArray [2]` 16 ├──────────────────┤│ 303 │ - `intArray [3]` 20 └──────────────────┘

Sekarang, jika Anda meneruskan intArray fungsi lain, nilai yang dimasukkan ke dalam tumpukan adalah 0x4AA4C288, alamat array, bukan salinan array.

237
11 июля '09 в 20:03 2009-07-11 20:03 Jawaban diberikan oleh P Daddy pada 11 Juli 2009 di 20:03 2009-07-11 20:03

Ya, array akan berada di heap.

Int tidak akan ditempatkan di dalam array. Hanya karena tipe nilai ada di tumpukan tidak berarti itu akan ditempatkan di dalam kotak. Tinju hanya akan terjadi ketika tipe nilai, seperti int, ditugaskan untuk referensi objek tipe.

Sebagai contoh

Tidak dimasukkan:

 int i = 42; myIntegers[0] = 42; 

Kotak:

 object i = 42; object[] arr = new object[10]; // no boxing here arr[0] = 42; 

Anda juga dapat melihat posting Eric tentang topik ini:

21
11 июля '09 в 17:35 2009-07-11 17:35 jawabannya diberikan oleh JaredPar 11 Juli 2009 di 17:35 2009-07-11 17:35

Untuk memahami apa yang terjadi, berikut adalah beberapa fakta:

  • Suatu objek selalu menonjol di tumpukan.
  • Tumpukan hanya berisi objek.
  • Jenis nilai dialokasikan di tumpukan, atau bagian dari objek di tumpukan.
  • Array adalah objek.
  • Array hanya dapat berisi tipe nilai.
  • Referensi objek adalah jenis nilai.

Jadi, jika Anda memiliki array bi>

Jika Anda memiliki array string, ini benar-benar sebuah array referensi ke string. Karena referensi adalah tipe nilai, mereka akan menjadi bagian dari objek array di heap. Jika Anda meletakkan objek string dalam array, Anda benar-benar meletakkan referensi ke objek string dalam array, dan string akan menjadi objek terpisah di heap.

13
11 июля '09 в 18:49 2009-07-11 18:49 jawabannya diberikan oleh Guffa 11 Juli 2009 di 18:49 2009-07-11 18:49

Saya pikir pertanyaan Anda didasarkan pada pemahaman yang salah tentang tipe referensi dan nilai. Ini adalah sesuatu yang telah ditemukan oleh semua pengembang .NET dan Java.

Array hanyalah daftar nilai. Jika itu adalah array dari tipe referensi (katakanlah, string[] ), maka array adalah daftar referensi ke berbagai objek string pada heap, karena referensi adalah nilai dari tipe referensi. Di dalam tautan ini diimplementasikan sebagai petunjuk ke alamat dalam memori. Jika Anda ingin memvisualisasikan ini, array seperti itu akan terlihat seperti ini di memori (dalam tumpukan):

[ 00000000, 00000000, 00000000, F8AB56AA ]

Ini adalah larik string , yang berisi 4 referensi ke objek string pada heap (angka-angka di sini adalah heksadesimal). Saat ini, hanya string terakhir yang benar-benar menunjuk ke sesuatu (memori diinisialisasi dengan semua nol saat ditugaskan), array ini pada dasarnya adalah hasil dari kode ini di C #:

 string[] strings = new string[4]; strings[3] = "something"; // the string was allocated at 0xF8AB56AA by the CLR 

Array di atas akan berada dalam program 32-bit. Dalam program 64-bit, F8AB56AA akan dua kali lebih besar ( F8AB56AA akan menjadi 00000000F8AB56AA ).

Jika Anda memiliki array tipe nilai (misalnya, int[] ), maka array adalah daftar bi>

[ 00000000, 45FF32BB, 00000000, 00000000 ]

Ini adalah array dari 4 bi>

  int[] integers = new int[4]; integers[1] = 1174352571; // integers[1] = 0x45FF32BB would be valid too 

Array int[] ini juga akan disimpan di heap.

Sebagai contoh lain, memori array short[4] akan terlihat seperti ini:

[ 0000, 0000, 0000, 0000 ]

Karena nilai short adalah angka 2 byte.

Jika tipe nilai disimpan, itu hanya detail implementasi, karena Eric Lippert menjelaskan dengan sangat baik di sini , bukan perbedaan inheren antara nilai dan tipe referensi (yang merupakan perbedaan perilaku).

Ketika Anda melewatkan sesuatu ke suatu metode (apakah itu tipe referensi atau tipe nilai), itu menyalin nilai tipe yang sebenarnya diteruskan ke metode. Dalam kasus tipe referensi, nilai ini adalah referensi (anggap ini sebagai penunjuk ke sepotong memori, meskipun ini juga merupakan detail implementasi), dan dalam kasus tipe nilai, nilai adalah hal itu sendiri.

 // Calling this method creates a copy of the *reference* to the string // and a copy of the int itself, so copies of the *values* void SomeMethod(string s, int i){} 

Boxing hanya terjadi jika Anda mengonversi tipe nilai ke tipe referensi. Kode-kode ini adalah:

 object o = 5; 
7
11 июля '09 в 19:57 2009-07-11 19:57 jawabannya diberikan JulianR 11 Juli 2009 di 19:57 2009-07-11 19:57

Array integer dialokasikan di heap, tidak lebih, tidak lain. myIntegers merujuk ke awal bagian di mana int dialokasikan. Tautan ini ada di tumpukan.

Jika Anda memiliki larik objek dari tipe referensi, misalnya Object, myObjects [], yang terletak di stack, akan merujuk ke sekelompok nilai yang merujuk ke objek.

Untuk meringkas, jika Anda mengirimkan myIntegers ke beberapa fungsi, Anda hanya meneruskan tautan ke tempat di mana grup bi>

1
11 июля '09 в 17:38 2009-07-11 17:38 jawabannya diberikan Dykam 11 Juli 2009 di 17:38 2009-07-11 17:38

Dalam kode contoh Anda, tidak ada kotak.

Jenis nilai bisa berada di heap, sama seperti di array int Anda. Array dialokasikan pada heap, dan menyimpan int, yang merupakan tipe nilai. Isi array diinisialisasi dengan nilai default (int), yang ternyata nol.

Pertimbangkan kelas yang berisi tipe nilai:

 class HasAnInt { int i; } HasAnInt h = new HasAnInt(); 

Variabel h mengacu pada instance HasAnInt yang hidup di heap. Itu hanya memiliki tipe nilai. Ini sangat normal, "Aku" tinggal di tumpukan, seperti di ruang kelas. Dalam contoh ini, tidak ada tinju.

1
11 июля '09 в 18:07 2009-07-11 18:07 jawabannya diberikan oleh Curt Nichols 11 Juli 2009 di 18:07 2009-07-11 18:07

Cukup dikatakan kepada semua orang, tetapi jika seseorang mencari sampel dan dokumentasi yang jelas (tetapi tidak resmi) tentang heap, stack, variabel lokal, dan variabel statis, lihat artikel lengkap John Skit tentang Memori di .NET - apa yang terjadi di sana.

Kutipan:

  • Setiap variabel lokal (yaitu, dideklarasikan dalam suatu metode) disimpan di stack. Ini termasuk variabel tipe referensi - variabel itu sendiri ada di tumpukan, tetapi ingat bahwa nilai variabel tipe referensi hanya referensi (atau nol), dan bukan objek itu sendiri. Parameter metode juga dihitung sebagai variabel lokal, tetapi jika mereka dideklarasikan dengan pengubah ref, mereka tidak mendapatkan slotnya sendiri, tetapi menggunakan slot dengan variabel yang digunakan dalam kode panggilan. Untuk informasi lebih lanjut, lihat artikel saya tentang passing parameter.

  • Variabel instan untuk tipe referensi selalu di heap. Bahwa objek itu sendiri "hidup."

  • Variabel instan untuk tipe nilai disimpan dalam konteks yang sama dengan variabel yang menyatakan tipe nilai. Slot memori untuk mesin virtual secara efektif berisi slot untuk setiap bidang dalam mesin virtual tersebut. Ini berarti (dengan mempertimbangkan dua poin sebelumnya) bahwa variabel struct yang dideklarasikan di dalam metode akan selalu berada di stack, sedangkan variabel struktur yang merupakan bidang instance kelas akan berada di heap.

  • Setiap variabel statis disimpan di heap, terlepas dari apakah itu dinyatakan dalam tipe referensi atau tipe nilai. Hanya satu slot, tidak peduli berapa banyak instance yang dibuat. (Meskipun demikian, tidak harus ada instance yang dibuat untuk satu slot.) Rincian yang tepat dari tumpukan variabel yang hidup adalah kompleks, tetapi dijelaskan secara rinci dalam artikel MSDN tentang masalah ini.

1
09 апр. jawabannya diberikan gmaran23 09 April. 2013-04-09 10:43 '13 pada 10:43 2013-04-09 10:43

Ini adalah ilustrasi yang menggambarkan jawaban di atas @P Ayah

2019

06 дек. Balas diberikan oleh Youngmtool 06 Des 2017-12-06 04:00 '17 pukul 4:00 2017-12-06 04:00

Pertanyaan lain pada label atau Ajukan Pertanyaan