Apakah membuat metode statis menghemat memori di kelas Anda akan memiliki banyak contoh?

8

Menanggapi tanggapan Aaronaught terhadap pertanyaan di:

Tidak bisakah saya menggunakan semua metode statis?

Bukankah lebih sedikit memori yang digunakan untuk metode statis? Saya mendapat kesan bahwa setiap instance objek membawa versi executable sendiri dari fungsi anggota non-statis.

Terlepas dari berapa banyak overhead yang terlibat dalam memanggil metode statis, terlepas dari desain OO yang buruk, dan kemungkinan sakit kepala di jalan, bukankah itu menggunakan lebih sedikit memori saat runtime?

Berikut ini sebuah contoh:

Saya membuat vektor objek yang diinisialisasi nol. Setiap objek berisi satu data (segitiga yang terdiri dari sembilan ganda). Setiap objek diisi secara berurutan dari data yang dibaca dari file .stl. Hanya satu metode statis yang diperlukan. Desain OO yang tepat menentukan bahwa metode yang berhubungan dengan data secara langsung harus didistribusikan ke setiap objek. Berikut adalah solusi OO standar:

foreach(obj in vec) {
  obj.readFromFile(fileName);
}

Setiap obj membawa readFromFilekode kompilasi bersama data!

Memori lebih menjadi perhatian daripada kinerja dalam hal ini, dan ada BANYAK data pada sistem terbatas.

Solusi:

  1. Metode Namespace (bagus untuk C ++ tetapi tidak mungkin di Java)
  2. Salah satu metode statis di kelas obj. Kode yang dapat dieksekusi disimpan di satu tempat saat runtime. Ada overhead kecil untuk memanggil metode ini.
  3. Kelas induk dari mana obj diturunkan, yang berisi metode pribadi readFromFile. Panggil dengan super.callPrivateMethod()panggilan mana readFromFile. Berantakan, dan masih ada beberapa overhead memori di setiap objek.
  4. Laksanakan di readFromFileluar ruang lingkup obj, jadi di kelas vec atau di kelas panggilan. Ini, menurut saya, merusak enkapsulasi data.

Saya menyadari untuk sejumlah besar data, satu objek eksplisit untuk setiap segitiga bukanlah pendekatan terbaik. Ini hanya sebuah contoh.

panik
sumber
7
Dalam bahasa apa Anda berpikir bahwa kode tersebut digandakan untuk setiap contoh? Ini tidak terjadi di Java, C #, C ++.
joshp
2
Yah, itu mungkin terjadi dengan beberapa bahasa dinamis saat masih bayi, atau sebagai efek samping dari refleksi yang disalahgunakan. Tetapi secara umum, tidak, byte tidak akan jauh lebih besar dari byte yang dikandungnya.
Matthew Mark Miller
1
Satu-satunya bahasa yang saya tahu di mana Anda bisa mendapatkan perilaku membuang-buang memori ini adalah Javascript, tetapi bahkan kemudian Anda harus benar-benar gagal di O prototypal untuk melakukannya. Apa yang seharusnya Anda lakukan di JS adalah meletakkan (baik statis dan non-statis) metode pada objek prototipe, sehingga semua objek yang mewarisi dari prototipe itu akan berbagi satu fungsi tanpa duplikasi.
Ixrec
2
Sudahkah Anda mempertimbangkan untuk menulis program kecil yang menciptakan ribuan objek seperti itu dan melakukan pengukuran sendiri?
Bryan Oakley
1
Bukan jawaban untuk setiap pertanyaan terkait OO: Injeksi Ketergantungan? Jika Anda terganggu dengan overhead memori Anda bisa mendesain objek "saver" yang Anda buat satu contoh, yang dapat disuntikkan ....
Pieter B

Jawaban:

19

Metode tidak disimpan pada basis per instance, bahkan dengan metode virtual. Mereka disimpan di satu lokasi memori, dan mereka hanya "tahu" objek mana yang mereka miliki karena thispointer dilewatkan ketika Anda memanggil mereka.

Satu-satunya memori tambahan yang diperlukan dalam C ++ adalah jika Anda menggunakan metode virtual, yang memerlukan satu pointer ekstra per instance untuk menunjuk pada tabel metode virtual (di Jawa tentu saja Anda selalu memiliki kelas dasar dengan metode virtual Object, sehingga tidak dapat dihindari ).

Jika berhasil seperti yang Anda gambarkan, bahasa OO tidak akan terlalu populer! Jangan ragu untuk menambahkan metode sebanyak yang Anda butuhkan ke objek Anda. Itu tidak akan mempengaruhi penggunaan memori mereka.

vrostu
sumber
Ada juga overhead metode per-virtual untuk setiap kelas. Dan Java adalah virtual secara default ...
Deduplicator
1
@Dupuplikator: Itu benar, tetapi Anda juga bisa berpendapat bahwa ada overhead untuk memiliki fungsi / metode di tempat pertama. Setiap fungsi membutuhkan memori dan fungsi virtual membutuhkan sedikit lebih banyak (sekitar 4 byte).
Bart van Ingen Schenau
@ BartvanIngenSchenau Atau 8 byte, dan untuk setiap kelas turunan lagi. Meskipun kedua perkiraan tersebut sangat meremehkan biaya di Jawa ...
Deduplicator
3
@Dupuplikator Tetap, biaya itu adalah per kelas (dan per kelas turunan), bukan per instance.
Craig
7

Terlepas dari berapa banyak overhead yang terlibat dalam memanggil metode statis, terlepas dari desain OO yang buruk, dan kemungkinan sakit kepala di jalan, bukankah itu menggunakan lebih sedikit memori saat runtime?

Ini agak rumit, tetapi saya akan mengatakan "kebanyakan tidak".


sumber
2

Suatu metode harus "statis" (banyak bahasa menggunakan istilah "metode kelas" yang jauh lebih baik) jika itu tidak merujuk ke turunan dari kelas. Ini harus menjadi metode instance jika mengacu pada instance kelas.

Membuat keputusan desain berdasarkan kemungkinan yang tidak jelas dari penghematan memori alih-alih penggunaan metode kelas yang tepat dan metode instance adalah ide yang sangat, sangat, sangat buruk.

gnasher729
sumber
2
Saran yang bagus, tetapi sebenarnya tidak menjawab pertanyaan.
JacquesB
1
Dengan asumsi kuat bahwa ini adalah pertanyaan XY, itu benar.
gnasher729
1

Pada prinsipnya, hanya ada satu salinan kode, apakah itu fungsi anggota statis atau tidak:

  • Di C ++ Anda dapat dengan mudah memverifikasi ini dengan melihat daftar assembler dari kode yang dihasilkan.
  • Saya bukan ahli Java, tetapi dari spesifikasi JNI Anda dapat menyimpulkan bahwa itu logika yang sama: Anda dapat mengambil referensi tunggal ke suatu fungsi dan menyebutnya berkali-kali untuk objek yang berbeda (meneruskannya sebagai referensi kelas sebagai argumen, serta referensi objek jika ini bukan metode statis).

Dengan menggunakan fungsi statis atau non-statis karenanya tidak akan mengubah jejak memori.

Sebenarnya ada perbedaan yang sangat sangat kecil, baik dalam kode yang dihasilkan maupun dalam memori yang dikonsumsi pada stack selama waktu eksekusi fungsi:

  • Panggilan ke fungsi non-statis harus melewati referensi / pointer ke objek di mana fungsi / metode ini diterapkan. Ini biasanya membutuhkan dorongan tambahan dan instruksi pop dalam urutan panggilan.
  • Panggilan ke fungsi statis tidak memerlukan overhead ini.

Tapi ini benar-benar dapat diabaikan: kita berbicara tentang satu atau dua instruksi mesin lebih atau kurang dibandingkan dengan kode lengkap. Jadi itu jelas bukan sesuatu yang perlu dikhawatirkan.

Perbedaan konsumsi tumpukan pada saat run-time terbatas pada waktu pelaksanaan fungsi, dengan ukuran pointer. Ini juga dapat diabaikan, kecuali jika Anda memikirkan fungsi yang disebut secara berulang berkali-kali (beberapa juta kali).

Jadi sebagai kesimpulan, saya sepenuhnya berbagi pendapat gnasher729 : optimasi prematur adalah akar dari semua kejahatan. Jika fungsi tidak bergantung pada objek, buatlah statis dan itu seharusnya menjadi satu-satunya kriteria.

Christophe
sumber
Saya percaya kompiler C ++ mungkin menghindari melewatkan referensi this, jika tidak digunakan dalam fungsi. Di Jawa mungkin JIT bisa melakukan ini.
Oliv
0

Sangat mudah untuk fokus pada hal-hal seperti mengoptimalkan penggunaan memori atau mengurangi baris kode tetapi ketika Anda mulai harus memelihara program yang orang-orang gunakan / hancurkan dan programmer lain menambahkan fungsionalitas ke ... dan mungkin memperkenalkan bug ... bukan program asli Anda mungkin saja ada bug yang berhasil melewati pengujian, Anda akan melihat bahwa fokus pada keterbacaan / pemeliharaan kode mungkin lebih penting. Saya bisa membuat bit array berkecepatan tinggi untuk melacak serangkaian titik data tetapi kecuali saya membungkus bit array itu dalam suatu objek dengan pengakses yang dapat dimengerti, programmer berikutnya akan menyentuh kode yang mungkin tidak akan menggunakannya, menggantinya, atau melakukan sihir mengerikan untuk itu. .

Jamy Spencer
sumber