Berbagi teknologi

Pertanyaan Wawancara Pengembangan Game 7

2024-07-08

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Seperti apa struktur data ArrayList yang mendasarinya?

Lapisan bawah ArrayList diimplementasikan berdasarkan array. Hal ini dilakukan dengan memperluas atau mengurangi ukuran array secara dinamis. Jika kapasitasnya tidak mencukupi, maka akan dibuat array yang lebih besar, lalu menyalin data asli, dan terakhir menambahkan data baru ke dalamnya.

Mekanisme perluasan ArrayList adalah: ketika elemen pertama ditambahkan, kapasitas ArrayList adalah 10; setiap kali elemen baru ditambahkan, jika kapasitas terlampaui, kapasitas asli akan menjadi dua kali lipat, yaitu kapasitas asli * 2; , jika kapasitas aslinya 0, maka kapasitas barunya adalah 1.

Keuntungan dan kerugian mekanisme perluasan ArrayList:

keuntungan:
  1. Mekanisme perluasan ArrayList mudah dipahami dan diterapkan.
  2. Kapasitas yang diperluas harus lebih besar dari kapasitas aslinya, yang dapat mengurangi jumlah salinan array saat menambahkan elemen baru dan meningkatkan efisiensi penambahan elemen.
kekurangan:
  1. Mekanisme perluasan ArrayList menyebabkan pemborosan memori dan dapat dengan mudah menyebabkan pemborosan ruang memori.
  2. Ketika kapasitasnya besar, setiap perluasan memerlukan memori dan sumber daya CPU yang besar, yang akan mempengaruhi kinerja. Oleh karena itu, saat menggunakan ArrayList, kapasitas awal perlu diatur dengan tepat.
ArrayList tidak aman untuk thread

Implementasi internal ArrayList didasarkan pada array. Ketika beberapa thread mengakses ArrayList yang sama pada saat yang sama, ketidakkonsistenan data dapat terjadi. Misalnya, ketika satu thread membaca data ArrayList, dan thread lain menambahkan/menghapus data di ArrayList, mungkin ada Ubah data di ArrayList, sehingga thread yang membaca data ArrayList mungkin membaca data yang salah, menyebabkan kesalahan program.

Metode umum untuk mengatasi ketidakamanan thread ArrayList meliputi:
  1. Gunakan Vektor alih-alih ArrayList: Vektor disinkronkan dan semua metode dimodifikasi dengan disinkronkan, sehingga aman untuk thread;
  2. Bungkus ArrayList menjadi keamanan thread: Gunakan metode Collections.synchronizedList(list) untuk mengubah ArrayList menjadi keamanan thread;
  3. Gunakan CopyOnWriteArrayList: Ini adalah koleksi yang aman dan efisien. Operasi penulisannya diimplementasikan dengan menyalin array yang mendasarinya. Biaya implementasi ini berada dalam kisaran yang dapat diterima.
  4. Gunakan kunci untuk mencapai keamanan thread: Anda dapat menggunakan mekanisme kunci seperti ReentrantLock untuk mengimplementasikan ArrayList yang aman untuk thread.

Perbedaan antara tumpukan dan tumpukan

  • Tumpukan adalah tabel linier khusus, ciri-cirinya adalah data hanya dapat dimasukkan dan dihapus pada satu ujung, berdasarkan prinsip masuk pertama, keluar terakhir, masuk terakhir keluar pertama. Ini adalah struktur penyimpanan yang dapat digunakan untuk menyimpan nilai parameter fungsi, variabel lokal, dll.

  • Heap adalah struktur pohon khusus yang dicirikan oleh fakta bahwa nilai semua node lebih besar atau sama dengan nilai node turunannya, dan nilai node akar adalah yang terbesar atau terkecil. Heap adalah struktur penyimpanan dinamis yang dapat digunakan untuk menyimpan data dalam jumlah besar, seperti pengurutan, pencarian, dll.

Lapisan bawah coroutine

Inti dari coroutine adalah thread yang ringan. Setiap coroutine memiliki tumpukan untuk menyimpan fungsi dan parameternya, variabel lokal, dll. Coroutine dapat ditangguhkan, dilanjutkan, dan dialihkan.

Prinsip C# GC (pengumpulan sampah).

  1. Penghitungan referensi: Ketika suatu objek direferensikan, jumlah referensinya bertambah 1. Ketika referensi menjadi tidak valid, jumlah referensinya dikurangi 1. Jika jumlah referensi suatu objek menjadi 0, objek tersebut akan diambil kembali oleh pemulung.
  2. Mark-and-clear: Saat pengumpul sampah sedang berjalan, ia melintasi objek sesuai dengan hubungan referensi, menandai objek yang dapat diakses sebagai "hidup", menandai objek yang tidak dapat diakses sebagai "mati", dan kemudian menghapus semua objek yang ditandai sebagai "mati".
  3. Algoritme penyalinan: Pengumpul sampah membagi memori yang tersedia menjadi dua blok, dan hanya menggunakan satu blok pada satu waktu. Jika ruang tidak mencukupi, objek yang masih ada akan disalin ke blok ruang lain, dan kemudian objek yang disalin akan dihapus dari aslinya ruang angkasa.
  4. Algoritme pelengkap tanda: Saat pengumpul sampah berjalan, pertama-tama ia akan menandai semua objek yang masih hidup, lalu memindahkan semua objek yang masih hidup ke satu ujung untuk membersihkan fragmen ruang yang tidak terpakai.

Perbedaan antara sinkronisasi status dan sinkronisasi bingkai

Sinkronisasi negara Ini mengacu pada transmisi status (seperti posisi, kecepatan, akselerasi, dll.) setiap mesin dalam sistem multi-mesin ke mesin lain dalam setiap siklus kontrol, sehingga setiap mesin tetap tersinkronisasi. Sinkronisasi status dapat mencapai kinerja kontrol kolaboratif multi-mesin secara real-time, tetapi karena sejumlah besar data perlu dikirim dalam setiap siklus kontrol, keakuratannya mungkin relatif rendah.

Sinkronisasi bingkai Artinya dalam setiap siklus kendali, perintah kendali setiap mesin pada sistem multimesin ditransmisikan ke mesin lain sehingga setiap mesin tetap tersinkronisasi. Sinkronisasi bingkai dapat mencapai keakuratan kontrol kolaboratif multi-mesin, namun karena hanya sejumlah kecil perintah kontrol yang dikirimkan dalam setiap siklus kontrol, kinerja real-time mungkin relatif rendah.

Pola desain umum

Pola Tunggal
Pola Pabrik
Pola Komposit
Pola Proksi

Karakteristik daftar tertaut, pohon biner, dan tabel hash

1. Daftar tertaut:
  • Ini adalah struktur daftar linier, yang ditandai dengan setiap node memiliki penunjuk yang menunjuk ke node berikutnya, sehingga membentuk daftar tertaut;
  • Terlepas dari menyisipkan atau menghapus sebuah node, Anda hanya perlu mengubah penunjuknya, dan kompleksitas waktunya adalah O(1);
  • Kompleksitas waktu untuk menemukan sebuah node adalah O(n), dan Anda perlu mencari secara berurutan mulai dari node kepala;
  • Daftar tertaut tidak perlu mempertimbangkan masalah alokasi ruang. Umumnya, alokasi memori dinamis digunakan untuk mencapai manajemen memori yang fleksibel.
2. Pohon biner:
  • Pohon biner adalah struktur pohon yang setiap simpulnya mempunyai paling banyak dua anak;
  • Kompleksitas waktu operasi pencarian, penyisipan dan penghapusan pohon biner masing-masing adalah O(log2n), O(log2n) dan O(log2n);
  • Karena setiap node pada pohon biner tidak disimpan secara terus menerus, tetapi disimpan secara hierarki, dan setiap node hanya dapat memiliki dua anak, ruang penyimpanan dapat digunakan dengan lebih efisien.
3. Tabel hash:
  • Tabel hash adalah struktur data yang memetakan kunci ke lokasi dalam tabel untuk mengakses catatan guna mempercepat pencarian;
  • Kompleksitas waktu pencarian tabel hash adalah O(1), dan kompleksitas waktu penyisipan dan penghapusan adalah O(n);
  • Implementasi tabel hash memerlukan ruang tambahan untuk menyimpan tabel hash itu sendiri, dan masalah tabrakan hash perlu diselesaikan.

Prinsip yang mendasari HashMap

Lapisan bawah HashMap diimplementasikan menggunakan daftar tertaut array (pohon merah-hitam). Ia menyimpan data sesuai dengan nilai kode hash dari kunci. Ia dapat menghitung posisi data dalam array (konflik hash) berdasarkan hash kode, dan menggunakan daftar tertaut (pohon merah-hitam) untuk menyimpan data. HashMap Di Java 8, ketika panjang daftar tertaut melebihi ambang batas (defaultnya adalah 8), daftar tersebut akan diubah menjadi pohon merah-hitam untuk meningkatkan efisiensi kueri.Jika kapasitasnya tidak mencukupi, maka secara otomatis akan bertambah. Faktor beban default adalah 0,75, dan metode perluasannya adalah 2 kali lipat kapasitas.

Cara menentukan apakah daftar tertaut memiliki siklus

  1. Gunakan tabel hash untuk melintasi setiap node dalam daftar tertaut dan menyimpan alamat node dalam tabel hash. Jika node saat ini sudah ada di tabel hash, berarti daftar tertaut memiliki siklus;
  2. Tentukan dua penunjuk, penunjuk lambat bergerak selangkah demi selangkah, dan penunjuk cepat bergerak dua langkah sekaligus. Jika penunjuk cepat bertemu dengan penunjuk lambat, berarti daftar tertaut memiliki siklus.

Apa saja skenario penggunaan tumpukan dan antrian?

Fungsi maju dan mundur browser: Halaman web yang dikunjungi browser dapat mewujudkan fungsi maju dan mundur melalui struktur data tumpukan.

Apakah Anda tahu sesuatu tentang masalah lengket tcp?

Masalah lengket TCP mengacu pada fakta bahwa protokol TCP tidak memfragmentasi data saat mentransmisikan data, menyebabkan jumlah data yang diterima oleh pihak penerima lebih besar daripada jumlah data yang dikirim oleh pihak pengirim.

Cara mengatasi masalah TCP Sticky adalah :
  1. Tambahkan pembatas di sisi pengiriman: Tambahkan pembatas di sisi pengiriman. Setelah pihak penerima menerima pembatas, ia dapat membagi data berdasarkan pembatas tersebut.
  2. Tambahkan header di ujung pengiriman: Pihak pengirim menambahkan header sebelum mengirim data. Header berisi informasi panjang data saat ini.
  3. Tambahkan buffer di ujung pengiriman: Sebelum mengirim data, pihak pengirim terlebih dahulu memasukkan data ke dalam buffer, dan hanya mengirimkan sebagian data di buffer setiap kali. Setelah menerima data, pihak penerima menentukan apakah akan mengirim data berdasarkan total panjang data yang lengkap.

Bagaimana mengimplementasikan TCP sederhana menggunakan UDP

Pertama-tama, datagram UDP dapat membantu mengimplementasikan proses jabat tangan tiga arah dalam protokol TCP/IP. Pada jabat tangan pertama, klien mengirimkan datagram UDP yang berisi permintaan jabat tangan. Ketika server menerima pesan ini, server akan membalas dengan pesan konfirmasi, yang menunjukkan bahwa server telah menerima permintaan jabat tangan klien dan siap memberikan layanan. Pada jabat tangan kedua, klien akan mengirimkan datagram UDP lagi. Kali ini pesan berisi beberapa informasi berguna, seperti alamat IP klien, nomor port, dll, sehingga server dapat mengidentifikasi klien. Pada jabat tangan ketiga, server akan mengirimkan datagram UDP yang menunjukkan bahwa koneksi telah dibuat dan klien dapat mulai mengirim data.

Kedua, datagram UDP juga dapat membantu mewujudkan proses transmisi data dalam protokol TCP/IP. Ketika klien perlu mengirim data ke server, data tersebut akan dienkapsulasi menjadi datagram UDP dan dikirim ke server; setelah server menerima datagram UDP, server akan mengurai data yang terdapat dalam pesan dan melakukan pemrosesan terkait.

Terakhir, datagram UDP juga dapat membantu mengimplementasikan proses terminasi dalam protokol TCP/IP.Ketika klien tidak perlu lagi berkomunikasi dengan server, ia dapat mengirimkan datagram UDP untuk menunjukkan bahwa klien mengakhiri koneksi. Setelah server menerima pesan ini, ia akan melepaskan sumber daya yang sesuai, sehingga menyelesaikan seluruh protokol TCP/IP .proses koneksi

Sudahkah Anda menggunakan coroutine? Mengapa menggunakan coroutine?Mengapa coroutine lebih cepat

Coroutine memungkinkan program untuk beralih di antara tugas-tugas yang berbeda, sehingga meningkatkan efisiensi program dan mengurangi waktu berjalan program. Coroutine memungkinkan program untuk beralih di antara beberapa tugas alih-alih menunggu satu tugas selesai sebelum memulai tugas lainnya. Itu juga dapat berbagi variabel antar thread yang berbeda, sehingga mengurangi waktu berjalannya program. Untuk aplikasi multitugas, penggunaan coroutine dapat meningkatkan kinerja secara signifikan, sehingga menghasilkan kecepatan berjalan yang lebih cepat.

Apakah lebih cepat melintasi array atau daftar tertaut dengan panjang yang sama? Mengapa?

Array lebih cepat, karena alamat setiap elemen array bersifat kontinu dan tetap, dan alamat elemen berikutnya dapat diperoleh dengan cepat, sedangkan alamat setiap elemen daftar tertaut terputus-putus, dan Anda perlu melintasi penunjuk untuk mendapatkan alamat elemen berikutnya, sehingga Traversing array lebih cepat.

Mari kita bicara tentang fungsi virtual. Mengapa kita memerlukan fungsi virtual?

Fungsi virtual adalah fungsi khusus yang berbeda dari fungsi biasa karena fungsi tersebut ditentukan secara otomatis oleh compiler dan dapat dipanggil pada waktu kompilasi. Karakteristik fungsi virtual adalah implementasinya ditentukan pada saat runtime, bukan pada waktu kompilasi.
Tujuan utama dari fungsi virtual adalah untuk mencapai polimorfisme. Kelas abstrak dapat mendefinisikan beberapa fungsi virtual, dan kemudian subkelasnya dapat mengimplementasikan fungsi tersebut.

Bisakah destruktor menjadi fungsi virtual? Apakah harus fungsi virtual? Mengapa? Apa masalahnya kalau bukan fungsi virtual?

Tidak harus berupa fungsi virtual, namun secara umum disarankan untuk menggunakan fungsi virtual, karena fungsi virtual dapat ditimpa oleh kelas turunan, sehingga destruktor dari kelas turunan dapat dijalankan dengan benar tidak digunakan, destruktor kelas turunan tidak akan dipanggil, yang dapat menyebabkan masalah seperti kebocoran memori.

Memperkenalkan alur rendering

Pipa rendering adalah serangkaian langkah yang digunakan untuk mengubah data adegan permainan dari informasi masukan menjadi gambar yang ditampilkan di layar.

Proses rendering pipeline dibagi menjadi tiga tahap utama yaitu tahap persiapan, tahap geometri, dan tahap lighting.

Pada fase persiapan, mesin game memuat model dan tekstur adegan game ke dalam unit pemrosesan grafis (GPU) dan mengatur data untuk digunakan pada fase berikutnya.

Pada tahap geometri, transformasi matriks digunakan untuk menempatkan model dalam ruang tiga dimensi dan mengubah model menjadi bentuk yang dapat didukung oleh piksel pada layar.

Pada tahap pencahayaan, sumber cahaya dan model pencahayaan digunakan untuk menghitung nilai warna setiap piksel, dan akhirnya gambar yang dihasilkan ditampilkan di layar.

Mari kita bicara tentang operasi penyisipan, kueri, dan penghapusan pohon pencarian biner, dan berapa kompleksitas waktunya?

  1. menyisipkan:
  • Kompleksitas waktu: O(log n)
  • Langkah:
  1. Perlakukan simpul yang akan disisipkan sebagai simpul daun baru, dimulai dari simpul akar;
  2. Jika nilai node yang akan dimasukkan lebih kecil dari nilai node saat ini, lanjutkan ke node anak kiri dari node saat ini;
  3. Jika nilai node yang akan dimasukkan lebih besar dari nilai node saat ini, lanjutkan ke node anak kanan dari node saat ini;
  4. Jika node saat ini tidak memiliki node anak, maka node yang akan dimasukkan akan menjadi node anak dari node saat ini;
  5. Jika tidak, ulangi langkah 2 hingga 4 hingga ditemukan node tanpa node anak, dan node yang akan disisipkan digunakan sebagai node anak dari node tersebut.

Bagaimana syarat algoritma serakah untuk mendapatkan solusi optimal?

Kondisi algoritma serakah untuk mendapatkan solusi optimal adalah "substruktur optimal" dan "properti seleksi serakah":

  1. Substruktur optimal: Solusi optimal terhadap suatu masalah berisi solusi optimal terhadap submasalah dari masalah tersebut;
  2. Properti seleksi serakah: Pada setiap langkah, pilihan optimal lokal dibuat, dan hasil akhirnya adalah solusi optimal global.