Ini pada dasarnya adalah aplikasi pencatatan / penghitungan yang menghitung jumlah paket dan menghitung jenis paket, dll. Pada jaringan obrolan P2P. Ini setara dengan sekitar 4-6 juta paket dalam periode 5 menit. Dan karena saya hanya mengambil "snapshot" dari informasi ini, saya hanya menghapus paket yang lebih lama dari 5 menit setiap lima menit. Jadi maksimum item yang akan ada dalam koleksi ini adalah 10 hingga 12 juta.
Karena saya perlu membuat 300 koneksi ke superpeers yang berbeda, ada kemungkinan setiap paket mencoba untuk dimasukkan setidaknya 300 kali (yang mungkin mengapa menyimpan data ini dalam memori adalah satu-satunya pilihan yang masuk akal).
Saat ini, saya telah menggunakan Kamus untuk menyimpan informasi ini. Tetapi karena sejumlah besar item yang saya coba simpan, saya mengalami masalah dengan tumpukan objek besar dan jumlah penggunaan memori terus bertambah seiring waktu.
Dictionary<ulong, Packet>
public class Packet
{
public ushort RequesterPort;
public bool IsSearch;
public string SearchText;
public bool Flagged;
public byte PacketType;
public DateTime TimeStamp;
}
Saya telah mencoba menggunakan mysql, tetapi tidak dapat mengikuti jumlah data yang perlu saya masukkan (sambil memeriksa untuk memastikan itu bukan duplikat), dan itu saat menggunakan transaksi.
Saya mencoba mongodb, tetapi penggunaan cpu untuk itu gila dan tidak menjaga keduanya.
Masalah utama saya muncul setiap 5 menit, karena saya menghapus semua paket yang lebih dari 5 menit, dan mengambil "snapshot" dari data ini. Karena saya menggunakan query LINQ untuk menghitung jumlah paket yang berisi jenis paket tertentu. Saya juga memanggil kueri () kueri yang berbeda pada data, di mana saya menghapus 4 byte (alamat ip) dari kunci keyvaluepair, dan menggabungkannya dengan nilai port requesting dalam Nilai keyvalupair dan menggunakannya untuk mendapatkan jumlah yang berbeda dari rekan dari semua paket.
Aplikasi saat ini melayang-layang sekitar 1,1GB penggunaan memori, dan ketika sebuah snapshot disebut itu bisa sejauh menggandakan penggunaan.
Sekarang ini tidak akan menjadi masalah jika saya memiliki jumlah ram yang gila, tetapi vm yang saya jalankan terbatas pada 2GB ram saat ini.
Apakah ada solusi mudah?
sumber
Jawaban:
Alih-alih memiliki satu kamus dan mencari kamus itu untuk entri yang terlalu lama; punya 10 kamus. Setiap 30 detik atau lebih, buat kamus "saat ini" baru dan buang kamus tertua tanpa pencarian sama sekali.
Selanjutnya, ketika Anda membuang kamus tertua, letakkan semua benda lama ke dalam antrian FILO untuk nanti, dan alih-alih menggunakan "baru" untuk membuat objek baru tarik objek lama dari antrian FILO dan gunakan metode untuk merekonstruksi yang lama objek (kecuali antrian objek lama kosong). Ini dapat menghindari banyak alokasi dan banyak overhead pengumpulan sampah.
sumber
Pikiran pertama yang muncul dalam pikiran adalah mengapa Anda menunggu 5 menit. Bisakah Anda melakukan snap-shot lebih sering dan dengan demikian mengurangi kelebihan besar yang Anda lihat pada batas 5 menit?
Kedua, LINQ bagus untuk kode ringkas, tetapi dalam kenyataannya LINQ adalah gula sintaksis pada "biasa" C # dan tidak ada jaminan bahwa itu akan menghasilkan kode yang paling optimal. Sebagai latihan Anda bisa mencoba dan menulis ulang hot spot dengan LINQ, Anda mungkin tidak meningkatkan kinerja tetapi Anda akan memiliki ide yang lebih jelas tentang apa yang Anda lakukan dan itu akan membuat pembuatan profil bekerja lebih mudah.
Hal lain yang harus dilihat adalah struktur data. Saya tidak tahu apa yang Anda lakukan dengan data Anda, tetapi bisakah Anda menyederhanakan data yang Anda simpan dengan cara apa pun? Bisakah Anda menggunakan array string atau byte dan kemudian mengekstrak bagian-bagian yang relevan dari item-item itu saat Anda membutuhkannya? Bisakah Anda menggunakan struct bukan kelas dan bahkan melakukan sesuatu yang jahat dengan stackalloc untuk menyisihkan memori dan menghindari GC berjalan?
sumber
Pendekatan sederhana: coba memcached .
The downside adalah bahwa itu berbasis memori dan tidak memiliki kegigihan. Jika sebuah instance turun, data hilang. Jika Anda membutuhkan kegigihan, buat serialisasi data sendiri.
Pendekatan yang lebih kompleks: coba Redis .
The downside adalah bahwa itu sedikit lebih kompleks.
sumber
Anda tidak harus menyimpan semua paket untuk pertanyaan yang telah Anda sebutkan. Misalnya - penghitung jenis paket:
Anda membutuhkan dua array:
Array pertama melacak berapa banyak paket dalam tipe yang berbeda. Array kedua melacak berapa banyak lagi paket yang ditambahkan dalam setiap menit sehingga Anda tahu berapa banyak paket yang perlu dihapus pada setiap interval menit. Saya harap Anda bisa mengatakan bahwa array kedua digunakan sebagai antrian FIFO bulat.
Jadi untuk setiap paket, operasi berikut dilakukan:
Kapan saja, penghitung paket dapat diambil oleh indeks secara instan dan kami tidak menyimpan semua paket.
sumber
(Saya tahu ini adalah pertanyaan lama, tetapi saya berlari melewatinya sambil mencari solusi untuk masalah serupa di mana pass pengumpulan sampah gen kedua menghentikan aplikasi selama beberapa detik, jadi merekam untuk orang lain dalam situasi yang sama).
Gunakan struct daripada kelas untuk data Anda (tapi ingat itu diperlakukan sebagai nilai dengan semantik pass-by-copy). Ini mengambil satu tingkat pencarian gc harus melakukan setiap tanda lulus.
Gunakan array (jika Anda tahu ukuran data yang Anda simpan) atau Daftar - yang menggunakan array secara internal. Jika Anda benar-benar membutuhkan akses acak cepat, gunakan kamus indeks array. Ini menghilangkan beberapa level (atau selusin atau lebih jika Anda menggunakan SortedDictionary) agar gc harus mencari.
Bergantung pada apa yang Anda lakukan, mencari daftar struct mungkin lebih cepat daripada pencarian kamus (karena lokalisasi memori) - profil untuk aplikasi khusus Anda.
Kombinasi struct & list mengurangi penggunaan memori dan ukuran penyapu sampah secara signifikan.
sumber