Bellek Depolama veri yapıları tasarlarken en iyi uygulamalar

*Bu içerik, yapay zekâ (beta) kullanılarak çevrildi ve hatalar içerebilir. Sayfayı İngilizce görüntülemek için buraya tıkla.

Veri yapısı türüne bağlı olarak, MemoryStoreService bellek ve bir veri yapısındaki öğe sayısı üzerinde sınırlamalar uygular. Tüm veri yapıları ayrıca küresel bir bölünme isteği sınırı tarafından da kısıtlanmaktadır.

Her Roblox oyununun Bellek Mağazası Gözetim Paneli bulunmaktadır. Bu panel, bellek mağazası kullanımını izlemek için kullanabileceğiniz bir dizi grafik içerir.

Sıralı haritalar ve kuyruklar

Sıralı haritalar ve kuyruklar, maksimum öğe sayısı ve maksimum toplam bellek üzerinde sınırlarla gelir. Ayrıca, bu veri yapılarındaki öğeler her zaman tek bir bölümde bulunur. Bu veri yapılarından yapılan her isteğin, aynı bölüme bir istek olduğu anlamına gelir.

Bir sıralı harita veya kuyruk öğe veya bellek sınırına ulaştığında, en iyi hareket tarzı gereksiz öğeleri manuel olarak kaldırmak veya öğeler için bir sona erme politikası eklemektir. Alternatif olarak, yalnızca bellek sınırı boğulmaya neden oluyorsa, anahtarlarınızdan ve değerlerinizden gereksiz bilgileri çıkararak öğelerinizin boyutunu azaltmayı deneyebilirsiniz.

Tüm öğelerinize ihtiyacınız varsa veya istek throughput'u nedeniyle boğulma yaşıyorsanız, tek çözüm parçalara ayırmadır.

Parçalara Ayırma

Parçalara ayırma, bir dizi ilişkili veriyi birden çok veri yapısına dağıtma sürecidir. Diğer bir deyişle, mevcut yüksek throughput'lu bir veri yapısını alıp, birlikte aynı veri kümesini içeren birden çok daha küçük veri yapısıyla değiştirmek anlamına gelir.

Parçalara ayırmanın temel zorluğu, verileri, orijinal yapının aynı işlevselliğini koruyacak bir şekilde birden fazla veri yapısına yayma yolunu bulmaktır.

Hash haritalarında, veri yapısı zaten bölümlendirilmiş olsa da, parçalara ayırma, istekleri birkaç anahtar arasında yayarak yapılır.

Sıralı Bir Haritayı Parçalara Ayırma

Bir sıralı haritayı parçalara ayırmak için verilerinizi karakter aralıklarıyla alfabetik alt bölümlere ayırmayı düşünün. Örneğin, yalnızca A'dan Z'ye ilk harfleri olan anahtarların olduğunu varsayalım ve mevcut kullanım durumunuz ve gelecekteki büyüme için dört sıralı haritanın yeterli olduğunu düşünüyoruz:

  • İlk harita A-G'yi, ikinci H-N'yi, üçüncü O-T'yi ve dördüncü U-Z'yi kapsayabilir.
  • Bir öğeyi eklemek veya almak için, öğenin başlangıç karakterine göre uygun haritayı kullanın.
Sıralı Bir Haritayı Parçalara Ayırma

-- Bellek Mağazası Servisini Başlat
local MemoryStoreService = game:GetService("MemoryStoreService")
-- Sıralı Harita kovalarınızı oluşturun
local sm_AtoG = MemoryStoreService:GetSortedMap("AtoG")
local sm_HtoM = MemoryStoreService:GetSortedMap("HtoM")
local sm_NtoT = MemoryStoreService:GetSortedMap("NtoT")
local sm_UtoZ = MemoryStoreService:GetSortedMap("UtoZ")
-- Yardımcı işlev, Öğenin Anahtarından doğru kovayı almak için
local function getSortedMapBucket(itemKey)
if (itemKey >= "a" and itemKey < "h") then
return sm_AtoG
elseif (itemKey < "n") then
return sm_HtoM
elseif (itemKey < "u") then
return sm_NtoT
else
return sm_UtoZ
end
end
-- Varsayılan değeri 0 olan oyuncu adlarını başlat
for _, player in game:GetService("Players"):GetPlayers() do
local bucket = getSortedMapBucket(player)
bucket:SetAsync(player, 0, 600)
end
-- Bir oyuncunun değerini alma
local player = "myPlayer"
local bucket = getSortedMapBucket(player)
local playerScore = bucket:GetAsync(player)
print(playerScore)

Bir Kuyruğu Parçalara Ayırma

Bir kuyruklu parçalara ayırma, sıralı bir haritayı parçalara ayırmaktan daha zordur. Talepleri birden fazla kuyruk arasında yaymak isteseniz de, eklemeler, okumalar ve kaldırmalar yalnızca kuyrukta ön veya arka kısımda gerçekleşir.

Bir çözüm, döner bir kuyruk kullanmaktır; bu, birden fazla kuyruk oluşturmayı ve bir öğe eklediğinizde veya okuduğunuzda bunlar arasında döndürmeyi içerir:

  1. Birkaç kuyruk oluşturun ve bunları bir dizide toplayın.

  2. İki yerel gösterici oluşturun. Biri, öğeleri okumak ve kaldırmak istediğiniz kuyruğu temsil eder. Diğeri, öğe eklemek istediğiniz kuyruğu temsil eder:

    • Okuma işlemleri için, her kuyruktan ihtiyaç duyduğunuz öğe sayısını ve okuma göstergesini nereye taşıyacağınızı hesaplayın.
    • Kaldırma işlemleri için, okunan kimlikleri her kuyruğa iletin.
    • Ekleme işlemleri için, ekleme göstericisindeki kuyruğa ekleyin ve göstericiyi artırın.
Bir Kuyruğu Parçalara Ayırma

-- Bellek Mağazası Servisini Başlat
local MemoryStoreService = game:GetService("MemoryStoreService")
-- Kuyruklarınızı oluşturun
local q1 = MemoryStoreService:GetQueue("q1")
local q2 = MemoryStoreService:GetQueue("q2")
local q3 = MemoryStoreService:GetQueue("q3")
local q4 = MemoryStoreService:GetQueue("q4")
-- Kuyrukları bir Diziye koyun
local queueArr = { q1, q2, q3, q4 }
-- Okuma ve ekleme kuyruklarının indekslerini temsil eden iki gösterici oluşturun
local readIndex = 1
local addIndex = 1
-- İndeksleri uygun şekilde güncelleyen yerel bir işlev oluşturun
local function rotateIndex(index, n)
return (index + n - 1) % 4 + 1
end
-- Kuyruktan n öğe okuyan yerel bir işlev oluşturun
local function readFromQueue(count, allOrNothing, waitTimeout)
local endIndex = count % 4
local countPerQueue = count // 4
local items = {}
local ids = {}
-- Her kuyrukta dön
for i = 1, 4, 1 do
-- Bu kuyruğun ekstra bir öğe okuyup okumayacağını belirleyin
local diff = i - readIndex
if diff < 0 then
diff += 4
end
local queue = queueArr[i]
-- Her kuyruktan öğeleri oku
-- Ekstra okuma kriterilerini karşılıyorsa +1 öğe
if diff < endIndex then
items[i], ids[i] = queue:ReadAsync(countPerQueue + 1, allOrNothing, waitTimeout)
else
items[i], ids[i] = queue:ReadAsync(countPerQueue, allOrNothing, waitTimeout)
end
end
readIndex = rotateIndex(readIndex, count)
return items, ids
end
-- Kuyruktan n öğeyi kaldıran yerel bir işlev oluşturun
local function removeFromQueue(ids)
for i = 1, 4, 1 do
local queue = queueArr[readIndex]
queue:RemoveAsync(ids[i])
end
end
-- Kuyruğa bir öğe ekleyen yerel bir işlev oluşturun
local function addToQueue(itemKey, expiration, priority)
local queue = queueArr[readIndex]
queue:AddAsync(itemKey, expiration, priority)
addIndex = rotateIndex(addIndex, 1)
end
-- Biraz kod yazın!
for _, player in game:GetService("Players"):GetPlayers() do
addToQueue(player, 600, 0)
end
local players, ids = readFromQueue(20, true, -1)
removeFromQueue(ids)

Hash Haritaları

Hash haritalarının bireysel bellek veya öğe sayısı sınırlamaları yoktur ve otomatik olarak parçalara ayrılır, ancak bunları kötü bir şekilde kullanıyorsanız yine de boğulma ile karşılaşabilirsiniz.

Örneğin, verilerin bir hash haritası olarak saklandığı ve metadata adında tek bir anahtarın değeri olarak depolandığı bir oyunu düşünün. Eğer bu metadata, yer kimliği, oyuncu sayısı gibi bilgilerin bulunduğu bir iç içe nesne içeriyorsa, metadata gerektiği her seferinde GetAsync("metadata") çağrısını yapmak zorundasınız ve tüm nesneyi almak zorundasınız. Bu durumda, tüm istekler tek bir anahtara ve dolayısıyla tek bir bölüme gider.

Tüm metadata'yı tek bir, iç içe nesne olarak depolamak yerine, her alanı kendi anahtarı olarak depolamak daha iyi bir yaklaşımdır; böylece hash haritası otomatik parçalara ayırma avantajından yararlanabilir. Metadata ile hash haritasının geri kalanı arasında ayrım yapmanız gerekiyorsa, bir isimlendirme öneki ekleyin (örneğin, metadata_user_count yerine sadece user_count).

Ayrıca, bir veya birkaç anahtar sıkça erişiliyorsa, bu çağrıları birçok anahtar arasında parçalara ayırmak önemlidir. Örneğin, tüm oyun sunucuları bir hash harita anahtarından bir değer almak zorundaysa, bölüm boğulması ile karşılaşabilirsiniz. Bunu önlemek için, o değerle aynı olan birkaç anahtar arasında bu çağrıları yayabilirsiniz, böylece bölme boğulması meydana gelmez.

©2026 Roblox Corporation. Roblox, the Roblox logo and Powering Imagination are among our registered and unregistered trademarks in the U.S. and other countries.