Halaman ini menjelaskan masalah kinerja umum dan praktik terbaik untuk menguranginya.
Perhitungan skrip
Operasi mahal dalam kode Luau membutuhkan waktu lebih lama untuk diproses dan dapat memengaruhi laju bingkai. Kecuali jika dieksekusi secara paralel, kode Luau dijalankan secara sinkron dan memblokir thread utama hingga menemukan fungsi yang menghasilkan thread.
Masalah umum
Operasi intensif pada struktur tabel - Operasi kompleks seperti serialisasi, deserialisasi, dan kloning dalam mendalam memerlukan biaya kinerja yang tinggi, terutama pada struktur tabel besar. Hal ini terutama benar jika operasi ini bersifat rekursif atau melibatkan iterasi pada struktur data yang sangat besar.
Peristiwa frekuensi tinggi - Mengaitkan operasi mahal dengan peristiwa berbasis bingkai RunService tanpa membatasi frekuensinya berarti operasi ini diulang setiap bingkai, yang sering kali mengakibatkan peningkatan waktu komputasi yang tidak perlu. Peristiwa ini mencakup:
Mitigasi
- Panggil kode pada peristiwa RunService secara hemat, membatasi penggunaan pada kasus-kasus di mana panggilan frekuensi tinggi sangat penting (misalnya, memperbarui kamera). Anda dapat mengeksekusi sebagian besar kode lain dalam peristiwa lain atau kurang sering dalam sebuah loop.
- Pecah tugas besar atau mahal menggunakan task.wait() untuk menyebarkan pekerjaan di beberapa bingkai.
- Identifikasi dan optimalkan operasi yang tidak perlu mahal dan gunakan multithreading untuk tugas komputasi mahal yang tidak perlu mengakses model data.
- Skrip tertentu di sisi server dapat memperoleh manfaat dari native code generation, sebuah flag sederhana yang mengkompilasi skrip menjadi kode mesin daripada bytecode.
Lingkup MicroProfiler
| Lingkup | Perhitungan terkait |
| RunService.PreRender | Kode yang dieksekusi pada peristiwa PreRender |
| RunService.PreSimulation | Kode yang dieksekusi pada peristiwa Stepped |
| RunService.PostSimulation | Kode yang dieksekusi pada peristiwa Heartbeat |
| RunService.Heartbeat | Kode yang dieksekusi pada peristiwa Heartbeat |
Untuk informasi lebih lanjut tentang debugging skrip menggunakan MicroProfiler, lihat pustaka debug, yang mencakup fungsi untuk menandai kode tertentu dan lebih meningkatkan spesifikasi, seperti debug.profilebegin dan debug.profileend. Banyak metode API Roblox yang dipanggil oleh skrip juga memiliki tag MicroProfiler terkait yang dapat memberikan sinyal yang berguna.
Penggunaan memori skrip
Bocornya memori dapat terjadi ketika Anda menulis skrip yang mengonsumsi memori yang tidak dapat dibebaskan oleh pengumpul sampah dengan benar ketika sudah tidak digunakan. Kebocoran ini terutama terjadi di server, karena server dapat terus online selama berhari-hari, sedangkan sesi klien jauh lebih singkat.
Nilai memori berikut dalam Konsol Pengembang dapat menunjukkan masalah yang perlu diselidiki lebih lanjut:
- LuaHeap - Konsumsi tinggi atau yang terus meningkat menyarankan adanya kebocoran memori.
- InstanceCount - Jumlah instansi yang terus meningkat menyarankan referensi terhadap beberapa instansi di kode Anda tidak dibebaskan oleh pengumpul sampah.
- PlaceScriptMemory - Menyediakan rincian penggunaan memori berdasarkan skrip.
Masalah umum
Meninggalkan koneksi tetap terhubung - Mesin tidak akan pernah mengumpulkan sampah peristiwa yang terhubung ke suatu instansi dan nilai-nilai apa pun yang dirujuk di dalam callback yang terhubung. Oleh karena itu, koneksi peristiwa dan kode aktif di dalam instansi yang terhubung, fungsi terhubung, dan nilai yang dirujuk, berada di luar jangkauan pengumpul sampah memori, bahkan setelah peristiwa dipicu.
Meskipun peristiwa terputus saat instansi yang dimilikinya dihancurkan, kesalahan umum adalah mengasumsikan bahwa ini berlaku untuk objek Player. Setelah seorang pengguna meninggalkan permainan, mesin tidak secara otomatis menghancurkan objek perwakilan Player mereka dan model karakter, sehingga koneksi ke objek Player dan instansi di bawah model karakter, seperti CharacterAdded, masih mengonsumsi memori jika Anda tidak memutuskan koneksinya di skrip Anda. Ini dapat mengakibatkan kebocoran memori yang sangat signifikan seiring waktu di server saat ratusan pengguna bergabung dan meninggalkan permainan.
Tabel - Menyisipkan objek ke dalam tabel tetapi tidak menghapusnya ketika tidak lagi dibutuhkan menyebabkan konsumsi memori yang tidak perlu, terutama untuk tabel yang melacak data pengguna saat mereka bergabung. Misalnya, contoh kode berikut membuat tabel yang menambahkan informasi pengguna setiap kali pengguna bergabung:
Contohlocal playerInfo = {}Players.PlayerAdded:Connect(function(player)playerInfo[player] = {} -- beberapa infoend)Jika Anda tidak menghapus entri ini ketika sudah tidak dibutuhkan, tabel terus tumbuh dalam ukuran dan mengonsumsi lebih banyak memori seiring semakin banyak pengguna bergabung dalam sesi. Kode apa pun yang beriterasi melalui tabel ini juga menjadi lebih mahal secara komputasi seiring pertumbuhan ukuran tabel.
Mitigasi
Untuk membersihkan semua nilai yang digunakan untuk mencegah kebocoran memori:
Putuskan semua koneksi - Telusuri basis kode Anda dan pastikan setiap koneksi dibersihkan melalui salah satu dari jalur berikut:
- Memutuskan secara manual menggunakan fungsi Disconnect().
- Menghancurkan instansi tempat peristiwa tersebut berada dengan fungsi Destroy().
- Menghancurkan objek skrip yang menjadi titik kembali koneksi.
Hapus objek dan karakter pemain setelah meninggalkan - Aktifkan Workspace.PlayerCharacterDestroyBehavior untuk secara otomatis menghancurkan objek pemain dan model karakter setelah pengguna meninggalkan. Jika Anda mau, Anda dapat membersihkannya secara manual:
Contoh pembersihan pemain dan karakterlocal Players = game:GetService("Players")Players.PlayerAdded:Connect(function(player)player.CharacterRemoving:Connect(function(character)task.defer(character.Destroy, character)end)end)Players.PlayerRemoving:Connect(function(player)task.defer(player.Destroy, player)end)
Perhitungan fisika
Simulasi fisika yang berlebihan dapat menjadi penyebab utama meningkatnya waktu komputasi per bingkai baik di server maupun klien.
Masalah umum
Frekuensi langkah waktu fisika yang berlebihan - Secara default, perilaku langkah berada dalam mode adaptif, di mana fisika melangkah pada 60 Hz, 120 Hz, atau 240 Hz, tergantung pada kompleksitas mekanisme fisika.
Mode tetap dengan akurasi fisika yang lebih baik juga tersedia, yang memaksa semua rakitan fisika untuk melangkah pada 240 Hz (empat kali per bingkai). Ini mengakibatkan lebih banyak komputasi setiap bingkai.
Jumlah kompleksitas objek yang disimulasikan berlebihan - Semakin banyak rakitan 3D yang disimulasikan, semakin lama waktu komputasi fisika diperlukan setiap bingkai. Sering kali, permainan akan memiliki objek yang disimulasikan yang tidak perlu disimulasikan atau akan memiliki mekanisme yang memiliki lebih banyak batasan dan sambungan daripada yang diperlukan.
Deteksi tabrakan yang terlalu presisi - Bagian mesh memiliki properti CollisionFidelity untuk mendeteksi tabrakan yang menawarkan berbagai mode dengan dampak kinerja yang berbeda. Mode deteksi tabrakan presisi untuk bagian mesh memiliki biaya kinerja yang paling mahal dan membutuhkan waktu lebih lama bagi mesin untuk menghitungnya.
Mitigasi
Pasang bagian yang tidak memerlukan simulasi - Pasang semua bagian yang tidak perlu digerakkan oleh fisika, seperti untuk NPC statis.
Gunakan langkah fisika adaptif - Langkah adaptif menyesuaikan secara dinamis laju perhitungan fisika untuk mekanisme fisika, memungkinkan pembaruan fisika dilakukan dengan kurang sering dalam beberapa kasus.
Kurangi kompleksitas mekanisme
- Di mana mungkin, minimalkan jumlah batasan fisika atau sambungan dalam rakitan.
- Kurangi jumlah tabrakan diri dalam mekanisme, seperti dengan menerapkan batasan atau batasan tanpa tabrakan pada anggota ragdoll untuk mencegah mereka saling bertabrakan.
Kurangi penggunaan presisi deteksi tabrakan untuk mesh
Untuk objek kecil atau tidak dapat diinteraksi di mana pengguna jarang memperhatikan perbedaan, gunakan presisi kotak.
Untuk objek ukuran kecil-menengah, gunakan presisi kotak atau hull, tergantung pada bentuk.
Untuk objek besar dan sangat kompleks, buat tabrakan khusus menggunakan bagian yang tidak terlihat jika memungkinkan.
Untuk objek yang tidak memerlukan tabrakan, nonaktifkan tabrakan dan gunakan presisi kotak atau hull, karena geometri tabrakan masih disimpan dalam memori.
Anda dapat merender geometri tabrakan untuk tujuan debug di Studio dengan mengalihkan Presisi tabrakan dari widget Opsi Visualisasi di sudut kanan atas viewport 3D.
Sebagai alternatif, Anda dapat menerapkan filter CollisionFidelity=PreciseConvexDecomposition ke Explorer yang menunjukkan jumlah semua bagian mesh dengan presisi presisi dan memungkinkan Anda untuk dengan mudah memilihnya.
Untuk panduan mendalam tentang cara memilih opsi presisi tabrakan yang menyeimbangkan kebutuhan presisi dan kinerja Anda, lihat Setel parameter fisika dan rendering.
Lingkup MicroProfiler
| Lingkup | Perhitungan terkait |
| physicsStepped | Perhitungan fisika keseluruhan |
| worldStep | Langkah fisika diskrit yang diambil setiap bingkai |
Penggunaan memori fisika
Gerakan fisika dan deteksi tabrakan mengonsumsi memori. Bagian mesh memiliki properti CollisionFidelity yang menentukan pendekatan yang digunakan untuk mengevaluasi batas tabrakan dari mesh.
Masalah umum
Mode deteksi tabrakan default dan presisi mengonsumsi memori yang jauh lebih banyak daripada dua mode lain dengan bentuk tabrakan yang lebih rendah.
Jika Anda melihat tingkat konsumsi memori yang tinggi di bawah PhysicsParts, Anda mungkin perlu menjelajahi pengurangan presisi tabrakan objek dalam permainan Anda.
Cara mitigasi
Untuk mengurangi memori yang digunakan untuk presisi tabrakan:
- Untuk bagian yang tidak memerlukan tabrakan, nonaktifkan tabrakannya dengan mengatur BasePart.CanCollide, BasePart.CanTouch dan BasePart.CanQuery ke false.
- Kurangi presisi tabrakan menggunakan pengaturan CollisionFidelity. Box memiliki beban memori terendah, dan Default dan Precise umumnya lebih mahal.
- Umumnya aman untuk mengatur presisi tabrakan bagian kecil yang ditetapkan ke Box.
- Untuk mesh besar yang sangat kompleks, Anda mungkin ingin membangun mesh tabrakan Anda sendiri dari objek yang lebih kecil dengan presisi tabrakan kotak.
Humanoid
Humanoid adalah kelas yang menyediakan berbagai fungsi untuk karakter pemain dan non-pemain (NPC). Meskipun kuat, Humanoid datang dengan biaya komputasi yang signifikan.
Masalah umum
- Meninggalkan semua HumanoidStateTypes aktif pada NPC - Ada biaya kinerja untuk membiarkan beberapa HumanoidStateTypes tetap aktif. Nonaktifkan yang tidak diperlukan untuk NPC Anda. Misalnya, kecuali NPC Anda akan memanjat tangga, aman untuk menonaktifkan keadaan Climbing.
- Membuat, memodifikasi, dan menghidupkan kembali model dengan Humanoids atau skinned MeshParts secara sering
- Ini bisa intensif untuk diproses mesin, terutama jika model-model ini menggunakan pakaian berlapis. Ini juga bisa menjadi masalah khusus dalam permainan di mana avatar sering kali respawn.
- Dalam MicroProfiler, tag updateInvalidatedFastClusters yang panjang (lebih dari 4 ms) sering kali menjadi sinyal bahwa instansiasi/modifikasi avatar memicu invalidasi yang berlebihan.
- Menggunakan Humanoids dalam kasus di mana mereka tidak diperlukan - NPC statis yang tidak bergerak umumnya tidak perlu menggunakan kelas Humanoid.
- Memutar animasi pada sejumlah besar NPC dari server - Animasi NPC yang dijalankan di server perlu disimulasikan di server dan direplikasi ke klien. Ini bisa mengakibatkan kelebihan beban yang tidak perlu.
- Melakukan perubahan ukuran dan skala yang tidak perlu - Perubahan ukuran/skala menyebabkan FastCluster dibangun kembali. Usahakan untuk mengurangi ini selama gameplay jika Anda melihat masalah kinerja terkait FastCluster. Demikian juga, perubahan properti lainnya mungkin juga menyebabkan FastCluster dibangun kembali, jadi secara umum kurangi perubahan ini sebanyak mungkin.
Mitigasi
- Putar animasi NPC di klien - Dalam permainan dengan sejumlah besar NPC, pertimbangkan untuk membuat Animator di klien dan menjalankan animasi secara lokal. Ini mengurangi beban di server dan kebutuhan untuk replikasi yang tidak perlu. Ini juga memungkinkan pengoptimalan tambahan (seperti hanya memutar animasi untuk NPC yang dekat dengan karakter).
- Gunakan alternatif ramah kinerja untuk Humanoids - Model NPC tidak harus mengandung objek humanoid.
- Untuk NPC statis, gunakan AnimationController sederhana, karena mereka tidak perlu bergerak tetapi hanya perlu memutar animasi.
- Untuk NPC yang bergerak, pertimbangkan untuk mengimplementasikan pengontrol gerakan Anda sendiri dan menggunakan AnimationController untuk animasi, tergantung pada kompleksitas NPC Anda.
- Nonaktifkan keadaan humanoid yang tidak digunakan - Gunakan Humanoid:SetStateEnabled() untuk hanya mengaktifkan keadaan yang diperlukan bagi setiap humanoid.
- Pembagian model NPC dengan respawn yang sering - Alih-alih menghancurkan NPC sepenuhnya, kirim NPC ke kolam NPC tidak aktif. Dengan cara ini, ketika NPC baru diperlukan untuk respawn, Anda cukup mengaktifkan kembali salah satu NPC dari kolam. Proses ini disebut pemrograman, yang meminimalkan jumlah kali karakter perlu diinstansiasi.
- Hanya spawn NPC saat pengguna berada di dekat - Jangan spawn NPC saat pengguna tidak dalam jangkauan, dan hilangkan mereka saat pengguna meninggalkan jangkauan mereka.
- Hindari membuat perubahan pada hierarki avatar setelah diinstansiasi - Beberapa modifikasi terhadap hierarki avatar memiliki implikasi kinerja yang signifikan. Beberapa optimasi tersedia:
- Untuk animasi prosedural kustom, jangan memperbarui properti JointInstance.C0 dan JointInstance.C1. Sebaliknya, perbarui properti Motor6D.Transform.
Lingkup MicroProfiler
| Lingkup | Perhitungan terkait |
| stepHumanoid | Kontrol dan fisika humanoid |
| stepAnimation | Animasi humanoid dan animator |
| updateInvalidatedFastClusters | Terhubung dengan instansiasi atau memodifikasi avatar |
Rendering
Sebagian besar waktu yang dihabiskan klien setiap bingkai digunakan untuk merender adegan dalam bingkai saat ini. Server tidak melakukan rendering, jadi bagian ini khusus untuk klien.
Panggilan gambar
Panggilan gambar adalah serangkaian instruksi dari mesin kepada GPU untuk merender sesuatu. Panggilan gambar memiliki biaya overhead yang signifikan. Umumnya, semakin sedikit panggilan gambar per bingkai, semakin sedikit waktu komputasi yang dihabiskan untuk merender bingkai.
Anda dapat melihat berapa banyak panggilan gambar yang terjadi saat ini dengan item Statistik Render ⟩ Timing di Studio. Anda dapat melihat Statistik Render di klien dengan menekan ShiftF2.
Semakin banyak objek yang perlu digambar di adegan Anda dalam suatu bingkai, semakin banyak panggilan gambar yang dibuat ke GPU. Namun, Mesin Roblox memanfaatkan proses yang disebut instansiasi untuk menggabungkan mesh identik dengan karakteristik tekstur yang sama ke dalam satu panggilan gambar. Secara khusus, beberapa mesh dengan MeshContent yang sama akan ditangani dalam satu panggilan gambar ketika:
- SurfaceAppearances identik jika ada, jika tidak, ketika TextureContents identik.
- Bahan adalah identik ketika baik SurfaceAppearance maupun MeshPart.TextureID tidak ada.
Masalah umum lainnya
Kepadatan objek yang berlebihan - Jika sejumlah besar objek terkonsentrasi dengan kepadatan tinggi, maka merender area adegan ini membutuhkan lebih banyak panggilan gambar. Jika Anda menemukan laju bingkai Anda turun saat melihat bagian tertentu dari peta, ini bisa menjadi sinyal baik bahwa kepadatan objek di area ini terlalu tinggi.
Objek seperti stiker, tekstur, dan partikel tidak dapat dikelompokkan dengan baik dan memperkenalkan panggilan gambar tambahan. Perhatikan jenis objek ini di dalam sebuah adegan. Khususnya, perubahan properti pada ParticleEmitters dapat memiliki dampak dramatis pada kinerja.
Peluang instansiasi yang terlewat - Sering kali, sebuah adegan akan mencakup mesh yang sama yang dikduplicate beberapa kali, tetapi setiap salinan mesh memiliki ID aset mesh atau tekstur yang berbeda. Ini mencegah instansiasi dan dapat menyebabkan panggilan gambar yang tidak perlu.
Penyebab umum dari masalah ini adalah ketika seluruh adegan diimpor sekaligus, daripada aset individu diimpor ke Roblox dan kemudian diduplikasi setelah diimpor untuk menyusun adegan.
Bahkan skrip sederhana seperti yang satu ini dapat membantu Anda mengidentifikasi bagian mesh dengan nama yang sama yang menggunakan ID mesh yang berbeda:
for _,descendant in workspace:GetDescendants() doif descendant:IsA("MeshPart") thenprint(descendant.Name .. ", " .. descendant.MeshId)endendOutput (dengan Stack Lines diaktifkan) mungkin terlihat seperti ini. Baris yang berulang menunjukkan penggunaan mesh yang sama, yang baik. Baris unik tidak selalu buruk, tetapi tergantung pada skema penamaan Anda, bisa menunjukkan adanya mesh duplikat dalam permainan Anda:
LargeRock, rbxassetid://106420009602747 (x144) -- baikLargeRock, rbxassetid://120109824668127LargeRock, rbxassetid://134460273008628LargeRock, rbxassetid://139288987285823LargeRock, rbxassetid://71302144984955LargeRock, rbxassetid://90621205713698LargeRock, rbxassetid://113160939160788LargeRock, rbxassetid://135944592365226 -- semua kemungkinan duplikatKompleksitas objek yang berlebihan - Meskipun tidak sepenting jumlah panggilan gambar, jumlah segitiga dalam adegan mempengaruhi berapa lama waktu yang dibutuhkan untuk merender bingkai. Adegan dengan jumlah mesh yang berjumlah sangat besar dan sangat kompleks adalah masalah umum, begitu juga dengan adegan dengan properti MeshPart.RenderFidelity diatur ke Precise pada terlalu banyak mesh.
Menyebabkan bayangan berlebihan - Menangani bayangan adalah proses yang mahal, dan peta yang mengandung sejumlah objek lampu yang tinggi dan berkepadatan yang menerapkan bayangan (atau sejumlah bagian kecil yang dipengaruhi oleh bayangan) dapat memiliki masalah kinerja.
Penggandaan transparansi yang tinggi - Menempatkan objek dengan transparansi sebagian berdekatan memaksa mesin untuk merender piksel yang tumpang tindih beberapa kali, yang dapat merugikan kinerja. Untuk informasi lebih lanjut tentang mengidentifikasi dan memperbaiki masalah ini, lihat Hapus transparansi berlapis.
Gerakan MeshPart yang tidak perlu - MeshPart yang dibungkus dalam Model tanpa Humanoid dikelompokkan menggunakan FastClusters yang diorganisir secara spasial. Ketika MeshParts ini bergerak, mereka harus terus-menerus ditambahkan dan dihapus dari kluster spasial ini, memaksa kluster dibangun kembali dan memengaruhi kinerja.
- Sebuah langkah yang sangat efektif adalah menyisipkan Humanoid ke dalam Model. Kehadiran Humanoid akan menggantikan perilaku pengelompokan spasial default, memaksa penggunaan satu FastCluster yang terintegrasi untuk seluruh Model. Dengan demikian, pembaruan posisi tidak lagi memerlukan pembangunan kembali kluster, sehingga mengurangi bottleneck performa. Teknik ini harus dikhususkan hanya untuk MeshParts yang diharapkan bergerak, karena dapat memperkenalkan overhead memori dan membatalkan manfaat optimisasi spasial. Kami merekomendasikan untuk selalu menganalisis permainan Anda setelah membuat perubahan jenis ini. Lihat tips kinerja Humanoid untuk informasi tambahan.
Terlalu banyak bagian dalam Model - Terlalu banyak bagian dalam sebuah Model bisa menyebabkan pembangunan kembali lebih sering karena potensi perubahan properti sebuah bagian yang memerlukan pembangunan kembali penuh. Temukan keseimbangan yang tepat dari bagian dalam Model saat menggunakan FastCluster.
Mitigasi
Instansiasi mesh identik dan mengurangi jumlah mesh unik - Jika Anda memastikan semua mesh identik memiliki ID aset yang sama, mesin dapat mengenali dan merender mereka dalam satu panggilan gambar. Pastikan untuk hanya mengupload setiap mesh dalam peta sekali dan kemudian menduplikasi mereka di Studio untuk digunakan kembali daripada mengimpor peta besar sebagai keseluruhan, yang mungkin menyebabkan mesh identik memiliki ID konten yang terpisah dan dikenali sebagai aset unik oleh mesin. Paket adalah mekanisme yang membantu untuk penggunaan ulang objek.
Pengurangan - Pengurangan menggambarkan proses menghilangkan panggilan gambar untuk objek yang tidak berkontribusi pada bingkai yang dirender akhir. Secara default, mesin melewati panggilan gambar untuk objek di luar bidang pandang kamera (pengurangan frustum) dan bagian, mesh, serta terrain yang terhalang dari pandangan oleh objek lain (pengurangan oklusi). Dalam skenario tertentu, seperti lingkungan dalam ruangan, Anda mungkin dapat menerapkan sistem ruangan atau portal dan secara manual mereduksi objek untuk lebih mengurangi panggilan gambar atau beban komputasi keseluruhan.
Mengurangi level detail untuk model - Aktifkan streaming instance dan setel properti LevelOfDetail model dunia Anda ke SLIM untuk merender mesh SLIM yang ringan dan dioptimalkan saat jarak dari kamera bertambah.
Mengurangi level detail untuk avatar - Aktifkan streaming instance dan setel Workspace.EnableSLIMAvatars untuk merender avatar platform sebagai representasi SLIM ringan dan dioptimalkan dengan dukungan animasi penuh saat jarak dari kamera bertambah.
Mengurangi presisi rendering - Atur MeshPart.RenderFidelity ke Automatic atau Performance. Ini memungkinkan mesh untuk kembali ke alternatif yang kurang kompleks, yang dapat mengurangi jumlah poligon yang perlu digambar.
Nonaktifkan pembuatan bayangan pada bagian dan objek lampu yang sesuai - Mesin Roblox secara otomatis menurunkan kualitas bayangan saat tingkat kualitas grafis klien menurun, akhirnya menonaktifkan bayangan sepenuhnya pada tingkat kualitas di bawah 4. Namun, Anda dapat secara selektif menonaktifkan properti pembuatan bayangan pada objek lampu dan bagian untuk meningkatkan kinerja saat bayangan diaktifkan dan meningkatkan kemungkinan bayangan tetap diaktifkan. Beberapa contoh optimasi yang dapat Anda lakukan baik pada waktu pengeditan atau dinamis saat runtime:
Gunakan properti BasePart.CastShadow untuk menonaktifkan pembuatan bayangan pada bagian kecil di mana bayangan tidak mungkin terlihat. Strategi ini sangat efektif ketika diterapkan pada bagian yang jauh dari kamera pengguna.
Nonaktifkan bayangan pada objek bergerak ketika memungkinkan.
Nonaktifkan Light.Shadows pada instansi lampu di mana objek tidak perlu membuat bayangan.
Batasi jangkauan dan sudut instansi lampu.
Gunakan lebih sedikit instansi lampu.
Pertimbangkan untuk menonaktifkan lampu yang berada di luar jangkauan tertentu atau secara spesifik berdasarkan ruangan untuk lingkungan dalam ruangan.
Lingkup MicroProfiler
| Lingkup | Perhitungan terkait |
| Prepare and Perform | Rendering keseluruhan |
| Perform/Scene/computeLightingPerform | Pembaruan grid cahaya dan bayangan |
| LightGridCPU | Pembaruan grid cahaya voxel |
| ShadowMapSystem | Pemetaan bayangan |
| Perform/Scene/UpdateView | Persiapan untuk rendering dan pembaruan partikel |
| Perform/Scene/RenderView | Rendering dan pengolahan pasca |
Jaringan dan replikasi
Jaringan dan replikasi menggambarkan proses pengiriman data antara server dan klien yang terhubung. Informasi dikirim antara klien dan server setiap bingkai, tetapi jumlah informasi yang lebih besar memerlukan lebih banyak waktu komputasi.
Masalah umum
Traffic jarak jauh yang berlebihan - Mengirim sejumlah besar data melalui objek RemoteEvent atau RemoteFunction atau memicunya sangat sering dapat menyebabkan sejumlah besar waktu CPU dihabiskan untuk memproses paket masuk setiap bingkai. Kesalahan umum termasuk:
- Mereplikasi data setiap bingkai yang tidak perlu direplikasi.
- Mereplikasi data berdasarkan input pengguna tanpa mekanisme untuk membatasinya.
- Mengalihkan lebih banyak data dari yang diperlukan. Misalnya, mengirim seluruh inventaris pemain saat mereka membeli item daripada hanya detail dari item yang dibeli.
Pembuatan atau penghapusan pohon instansi kompleks - Ketika sebuah perubahan dibuat pada model data di server, itu direplikasi ke klien yang terhubung. Ini berarti membuat dan menghancurkan hierarki instansi besar seperti peta pada saat runtime bisa sangat memakan jaringan.
Penyebab umum di sini adalah data animasi kompleks yang disimpan oleh plugin Animation Editor di rig. Jika ini tidak dihapus sebelum permainan diterbitkan dan model yang dianimasi sering diduplikasi, sejumlah besar data akan direplikasi tanpa perlu.
TweenService di sisi server - Jika TweenService digunakan untuk tween objek di sisi server, properti yang di tween direplikasi ke setiap klien setiap bingkai. Ini tidak hanya mengakibatkan tween yang goyang seiring fluktuasi latensi klien, tetapi juga menyebabkan banyak traffic jaringan yang tidak perlu.
Mitigasi
Anda dapat menerapkan taktik berikut untuk mengurangi replikasi yang tidak perlu:
- Hindari mengirim sejumlah besar data sekaligus melalui acara jarak jauh. Sebaliknya, hanya kirim data yang diperlukan dengan frekuensi lebih rendah. Misalnya, untuk status karakter, replikasi ketika ada perubahan daripada setiap bingkai.
- Pecah pohon instansi kompleks seperti peta dan muat dalam potongan untuk mendistribusikan pekerjaan replikasi ini di beberapa bingkai.
- Bersihkan metadata animasi, terutama direktori animasi rig, setelah mengimpor.
- Batasi replikasi instansi yang tidak perlu, terutama dalam kasus di mana server tidak perlu mengetahui instansi yang sedang dibuat. Ini termasuk:
- Efek visual seperti ledakan atau sihir. Server hanya perlu mengetahui lokasi untuk menentukan hasil, sementara klien dapat membuat visual secara lokal.
- Model item tampilan orang pertama.
- Tween objek di klien daripada di server.
Lingkup MicroProfiler
| Lingkup | Perhitungan terkait |
| ProcessPackets | Proses paket jaringan masuk, seperti pemicu peristiwa dan perubahan properti |
| Allocate Bandwidth and Run Senders | Peristiwa keluar yang relevan di server |
Penggunaan memori aset
Mekanisme dengan dampak tertinggi yang tersedia untuk pembuat untuk meningkatkan penggunaan memori klien adalah mengaktifkan streaming instance.
Streaming instansi
Streaming instansi memuat bagian dari model data yang tidak diperlukan secara selektif, yang dapat menyebabkan waktu muat yang sangat berkurang dan meningkatkan kemampuan klien untuk mencegah crash ketika mengalami tekanan memori.
Jika Anda mengalami masalah memori dan streaming instansi dinonaktifkan, pertimbangkan untuk memperbarui permainan Anda untuk mendukungnya, terutama jika dunia 3D Anda besar. Streaming instance didasarkan pada jarak dalam ruang 3D, jadi dunia yang lebih besar secara alami lebih diuntungkan darinya.
Jika streaming instansi diaktifkan, Anda dapat meningkatkan agresivitasnya. Misalnya, pertimbangkan:
- Mengurangi penggunaan Enum.ModelStreamingMode.Persistent jika memungkinkan. Anda mungkin perlu memperbarui skrip Anda jika Anda menggunakannya sebagai langkah kompatibilitas.
- Mengurangi Workspace.StreamingMinRadius dan Workspace.StreamingTargetRadius.
Untuk informasi lebih lanjut tentang opsi streaming dan manfaatnya, lihat properti streaming.
Masalah umum lainnya
Duplikasi aset - Kesalahan umum adalah mengupload aset yang sama beberapa kali yang menghasilkan ID aset yang berbeda. Ini dapat menyebabkan konten yang sama dimuat ke memori beberapa kali.
Volume aset yang berlebihan - Bahkan ketika aset tidak identik, terdapat kasus di mana peluang untuk menggunakan kembali aset yang sama dan menghemat memori terlewatkan.
File audio - File audio dapat menjadi kontributor yang mengejutkan terhadap penggunaan memori, terutama jika Anda memuat semuanya ke klien sekaligus daripada hanya memuat apa yang Anda butuhkan untuk sebagian permainan. Untuk strategi, lihat Waktu muat.
Tekstur resolusi tinggi - Konsumsi memori grafis untuk sebuah tekstur tidak berkaitan dengan ukuran tekstur di disk; jumlah piksel dalam tekstur menentukan penggunaan memori. Misalnya, tekstur 1024x1024 piksel mengonsumsi empat kali lebih banyak memori grafis dibandingkan tekstur 512x512.
Gambar yang diupload ke Roblox ditranskode ke format tetap, jadi tidak ada keuntungan memori dari mengupload gambar dalam model warna yang terkait dengan lebih sedikit byte per piksel. Begitu pula, mengompres gambar sebelum diupload atau menghapus saluran alfa dari gambar yang tidak memerlukannya dapat mengurangi ukuran gambar di disk, tetapi tidak memperbaiki penggunaan memori.
Saat permainan dimuat, mesin secara otomatis mulai dengan tekstur berkualitas rendah dan kemudian meningkatkan kualitas berdasarkan memori perangkat yang tersedia, jarak dari kamera, jumlah ruang layar yang diambil oleh tekstur, dan faktor lainnya. Sekalipun demikian, merencanakan ukuran tekstur Anda dapat meningkatkan penggunaan memori dalam permainan Anda.
Mitigasi
Hanya unggah aset sekali - Gunakan ID aset yang sama di seluruh objek dan pastikan aset yang sama, terutama mesh dan gambar, tidak diupload terpisah beberapa kali.
Temukan dan perbaiki aset duplikat - Cari bagian mesh dan tekstur identik yang diupload beberapa kali dengan ID yang berbeda.
- Meskipun tidak ada API untuk mendeteksi kesamaan aset secara otomatis, Anda dapat mengumpulkan semua ID aset gambar di tempat Anda (baik secara manual atau dengan skrip), mengunduhnya, dan membandingkannya menggunakan alat perbandingan eksternal.
- Untuk bagian mesh, strategi terbaik adalah mengambil ID mesh yang unik dan mengelompokkannya berdasarkan ukuran untuk mengidentifikasi duplikasi secara manual.
- Alih-alih menggunakan tekstur terpisah untuk warna yang berbeda, upload satu tekstur dan gunakan properti SurfaceAppearance.Color untuk menerapkan berbagai nuansa padanya.
Impor aset di peta satu per satu - Alih-alih mengimpor seluruh peta sekaligus, impor dan rekonstruksi aset dalam peta secara individu dan rekonstruksi mereka. Pengimpor tidak melakukan penghilangan duplikasi mesh, jadi jika Anda mengimpor peta besar dengan banyak ubin lantai terpisah, masing-masing ubin tersebut akan diimpor sebagai aset terpisah (meskipun mereka duplikat). Ini dapat menyebabkan masalah kinerja dan memori di kemudian hari, karena setiap mesh diperlakukan sebagai individu dan mengambil memori serta panggilan gambar.
Batasi piksel gambar tidak lebih dari jumlah yang dibutuhkan. Kecuali jika gambar menempati ruang fisik yang besar di layar, biasanya hanya butuh maksimal 512x512 piksel. Sebagian besar gambar kecil harus lebih kecil dari 256x256 piksel.
Gunakan lembar trim untuk memastikan penggunaan ulang tekstur maksimum dalam peta 3D. Untuk langkah-langkah dan contoh bagaimana cara membuat lembar trim, lihat Buat lembar trim.
Anda juga dapat mempertimbangkan untuk menggunakan lembar sprite untuk memuat banyak gambar UI kecil sebagai satu gambar. Anda kemudian dapat menggunakan ImageLabel.ImageRectOffset dan ImageLabel.ImageRectSize untuk menampilkan bagian dari lembar tersebut.
Waktu muat
Banyak permainan menerapkan layar pemuatan kustom dan menggunakan metode ContentProvider:PreloadAsync() untuk meminta aset sehingga gambar, suara, dan mesh diunduh di latar belakang.
Keuntungan dari pendekatan ini adalah memungkinkan Anda memastikan bagian penting dari permainan Anda sepenuhnya dimuat tanpa muncul tiba-tiba. Namun, kesalahan umum adalah memanfaatkan metode ini secara berlebihan untuk memuat lebih banyak aset daripada yang sebenarnya dibutuhkan.
Contoh praktik buruk adalah memuat seluruh Workspace. Meskipun ini mungkin mencegah pop-in tekstur, ini secara signifikan meningkatkan waktu muat.
Praktik serupa lainnya adalah memanfaatkan ContentProvider.RequestQueueSize untuk memastikan bahwa semua aset yang diminta telah selesai dimuat. Namun, ini menghadapi masalah yang sama dengan waktu muat yang meningkat secara signifikan, sementara juga menjadi metode yang tidak dapat diandalkan karena sifatnya yang berfluktuasi.
Sebaliknya, hanya gunakan ContentProvider:PreloadAsync() dalam situasi yang diperlukan, yang mencakup:
- Gambar di layar pemuatan.
- Gambar penting di menu permainan Anda, seperti latar belakang tombol dan ikon.
- Aset penting di area awal atau pemunculan.
Jika Anda harus memuat sejumlah besar aset, kami sarankan Anda menyediakan tombol Lewati Pemuatan.