
Kurumsal Node.js Projelerinde Bellek (Memory) Yönetimi
Diyarbakır Yazılım
16.08.2026
#Yazılım#Teknoloji#Topluluk
Bir Node.js servisi ilk günlerde 150 MB RAM ile sakin biçimde çalışırken birkaç hafta sonra 800 MB seviyelerine çıkıyorsa ilk tepki çoğu zaman heap limitini yükseltmek oluyor. Oysa production ortamında yüksek bellek tüketimi tek başına bir memory leak kanıtı değildir ve sorunu anlamadan limit artırmak yalnızca arızanın daha geç ortaya çıkmasına neden olabilir. Kurumsal Node.js Projelerinde Bellek (Memory) Yönetimi yaklaşımında heap, RSS, native memory, Buffer kullanımı, garbage collection, connection pool, queue ve container limitleri birlikte değerlendirilmelidir. Bu rehberde kurumsal Node.js uygulamalarında bellek yönetimi nasıl yapılır sorusunu V8 seviyesinden Kubernetes pod davranışına kadar adım adım ele alacağız. Amacımız yalnız leak bulmak değil, bellek kullanımını ölçülebilir bir production bütçesine dönüştürmek, performans düşüşlerini erken görmek ve incident anında hangi araca ne zaman başvuracağınızı netleştirmektir.
Node.js Bellek Yönetimi Nedir?
Node.js bellek yönetimi uygulamanın kullandığı JavaScript nesnelerinin yanı sıra Buffer alanlarını, native allocation'ları, kod belleğini, thread stack'lerini ve runtime overhead'ini birlikte yönetme sürecidir. Uygulama geliştiricisi JavaScript nesnelerini manuel olarak serbest bırakmaz çünkü V8 garbage collector artık erişilemeyen nesneleri otomatik olarak temizler. Buna rağmen açık bağlantılar, listener'lar, sınırsız cache'ler ve uzun ömürlü referanslar belleğin geri kazanılmasını engelleyebilir. Production sisteminde gerçek hedef mümkün olan en düşük RAM tüketimi değil, tahmin edilebilir ve sınırlandırılmış bir bellek profili oluşturmaktır. Bu yaklaşım availability, latency ve maliyet hedeflerinin aynı anda korunmasına yardımcı olur.
Node.js Belleği Nasıl Yönetir?
Node.js JavaScript nesnelerinin büyük bölümünü V8 tarafından yönetilen heap alanında tutar. Buffer, bazı native addon verileri ve runtime tarafından kullanılan başka alanlar ise V8 heap dışında bulunabilir. Bu nedenle yalnız heap grafiğine bakarak process belleğinin tamamını anlamak mümkün değildir. `process.memoryUsage()` gibi API'ler heap, RSS ve external memory arasında ayrım yaparak daha doğru bir başlangıç sağlar. Kurumsal sistemlerde bu değerlerin tek anlık ölçüm yerine trafik, GC ve latency metrikleriyle zaman serisi olarak izlenmesi gerekir.
V8 JavaScript Engine'in Rolü
V8 JavaScript kodunu çalıştırır, nesnelerin heap üzerindeki yaşam döngüsünü yönetir ve garbage collection süreçlerini yürütür. Sık kullanılan kod yollarını optimize ederek machine code üretmesi de runtime memory kullanımına katkıda bulunur. Heap yapısı kısa ömürlü ve uzun ömürlü nesnelerin farklı alanlarda yönetilmesine dayanır. Allocation davranışı değiştiğinde garbage collector'ın çalışma sıklığı ve süresi de değişebilir. Bu nedenle bir Node.js performans sorununda yalnız uygulama kodunu değil kullanılan Node.js ve dolayısıyla V8 sürümünü de hesaba katmak gerekir.
Otomatik Garbage Collection Nedir?
Garbage collection uygulamanın artık erişemediği JavaScript nesnelerinin belleğini otomatik olarak geri kazanan mekanizmadır. Bir nesneye GC root üzerinden ulaşılabiliyorsa nesne yaşamaya devam eder. Referans zinciri koptuğunda nesne sonraki uygun collection döngülerinden birinde temizlenebilir. Bu süreç geliştiricinin `free()` benzeri manuel bellek yönetimi yapma zorunluluğunu büyük ölçüde ortadan kaldırır. Yine de GC'nin ne kadar sık çalıştığını ve ne kadar bellek geri alabildiğini izlemek production memory davranışı hakkında önemli sinyaller verir.
Otomatik GC Neden Memory Leak'i Tamamen Önlemez?
Garbage collector yalnız gerçekten erişilemez hâle gelmiş nesneleri temizleyebilir. Global bir Map içinde unutulan kullanıcı verisi hâlâ reachable olduğu için GC açısından geçerli bir nesnedir. Aynı durum silinmeyen EventEmitter listener'ları, açık timer'lar veya kapanmayan socket state'leri için de geçerlidir. Bu nedenle JavaScript'teki memory leak çoğu zaman yanlış allocation'dan değil gereksiz referansın yaşamaya devam etmesinden kaynaklanır. Leak teşhisinde hangi nesnenin büyük olduğundan çok onu hangi retaining path'in hayatta tuttuğunu anlamak daha değerlidir.
Kurumsal Uygulamalarda Memory Yönetimi Neden Reliability Konusudur?
Bellek kullanımı kontrol dışına çıktığında sorun yalnız maliyet artışıyla sınırlı kalmaz. Heap pressure daha sık garbage collection oluşturabilir, event loop gecikebilir ve P99 latency yükselmeye başlayabilir. Container limitine ulaşan process OOM nedeniyle kapanabilir ve pod restart döngüsüne girebilir. Aynı anda birçok replica benzer biçimde davranırsa servis kapasitesi hızla düşebilir. Bu nedenle memory budget, OOM oranı, restart sayısı ve GC pause süreleri doğrudan reliability hedeflerinin bir parçası olarak ele alınmalıdır.
Node.js Process Belleğinin Bileşenleri
Bir Node.js process'in RAM kullanımı yalnız V8 heap değerinden oluşmaz. JavaScript heap yanında stack, native allocations, Buffer alanları, runtime code, shared libraries ve thread kaynakları da process RSS değerine katkıda bulunur. Bu ayrım özellikle heapUsed sabitken RSS yükselen incident'larda önemlidir. Tek bir memory metriği üzerinden alarm üretmek root cause'u yanlış sınıflandırabilir. Sağlıklı monitoring paneli process belleğini mümkün olduğunca bileşenlerine ayırmalı ve container limitini de aynı grafikte göstermelidir.
Stack
Stack function call frame'leri, local execution bilgileri ve çağrı zincirleri için kullanılan bellek alanıdır. JavaScript'te çok derin recursion stack overflow oluşturabilir ancak tipik memory leak vakalarının ana kaynağı stack değildir. Her worker thread veya native thread kendi stack alanına ihtiyaç duyabileceği için process thread sayısı arttığında toplam maliyet büyüyebilir. Stack kullanımını heap snapshot ile aynı şekilde analiz etmek mümkün değildir. Çok sayıda thread açan native kütüphaneler kullanılıyorsa process RSS bütçesinde thread stack maliyetine de yer ayrılmalıdır.
V8 Heap
V8 heap JavaScript object, array, closure ve pek çok runtime veri yapısının bulunduğu temel alandır. `heapUsed` aktif kullanılan heap miktarını, `heapTotal` ise V8 tarafından ayrılmış heap kapasitesinin önemli bölümünü gösterir. Heap GC tarafından yönetilir ve trafik sırasında büyüyüp collection sonrasında düşmesi normaldir. Tek seferlik yüksek `heapUsed` ölçümü leak anlamına gelmez. Asıl önemli sinyal benzer trafik koşullarında GC sonrasındaki baseline değerinin zaman içinde sürekli yükselmesidir.
Native Memory
Native memory C veya C++ tarafında ayrılan ve V8 heap dışında kalan alanları kapsayabilir. Node.js runtime, TLS, compression, database driver, image processing kütüphanesi veya native addon bu alanda allocation yapabilir. Böyle bir problemde `heapUsed` normal görünürken RSS sürekli büyüyebilir. Heap snapshot yalnız V8 object graph'ını gösterdiği için native leak doğrudan görünmeyebilir. Bu durumda process metrics, diagnostic report ve gerektiğinde platforma uygun native profiler araçları devreye alınmalıdır.
External Memory
`external` metriği V8 tarafından izlenen ancak JavaScript heap dışında bulunan belirli memory allocation'larını gösterir. Buffer ve ArrayBuffer ile ilişkili bellek bu kategorinin önemli bölümünü oluşturabilir. Büyük dosya, network payload veya binary işleme yapan servislerde external memory heapUsed kadar önemli bir sinyaldir. External değer artarken heap sabitse sorun JavaScript object leak olarak sınıflandırılmamalıdır. Production dashboard'da RSS, heapUsed ve external metriklerini aynı zaman aralığında görmek bu ayrımı hızlandırır.
Buffer ve ArrayBuffer
Node.js Buffer binary veri işlemek için kullanılan temel yapılardan biridir ve ArrayBuffer tabanlı bellekle ilişkilidir. Güncel `process.memoryUsage()` çıktısındaki `arrayBuffers` alanı Node.js Buffer'larını da kapsar ve bu değer `external` içinde de yer alır. Büyük upload, download, compression veya socket workload'larında Buffer allocation hızla büyüyebilir. Buffer referansları JavaScript object üzerinden tutulduğu sürece underlying bellek de serbest bırakılamayabilir. Bu nedenle binary workload'larda heap grafiği yanında `external`, `arrayBuffers` ve RSS birlikte izlenmelidir.
JIT / Code Memory
V8 çalıştırılan JavaScript kodu için bytecode ve optimize edilmiş machine code gibi yapılara bellek ayırır. Bu alan normal uygulama yaşam döngüsünün bir parçasıdır ve her artış leak anlamına gelmez. Çok büyük codebase, dynamic code generation veya çok sayıda farklı hot path toplam code memory miktarını etkileyebilir. `v8.getHeapCodeStatistics()` bazı code ve metadata ölçümlerini gözlemlemek için kullanılabilir. Incident analizinde bu alan genellikle cache veya Buffer leak kadar sık suçlu değildir fakat process budget hesaplanırken tamamen yok sayılmamalıdır.
Thread Stack'leri
Node.js ana JavaScript thread'i dışında libuv thread pool ve uygulamanın oluşturduğu worker thread'ler ek stack belleği kullanır. Worker Threads kullanıldığında her worker kendi V8 isolate ve heap alanına sahiptir. Bu nedenle yalnız process başına tek heap varmış gibi hesap yapmak worker yoğun sistemlerde yanıltıcı olur. Thread sayısı arttıkça stack ve isolate overhead'i de artar. Worker pool boyutu CPU sayısı kadar bellek bütçesine göre de sınırlandırılmalıdır.
process.memoryUsage() Nasıl Okunur?
`process.memoryUsage()` Node.js process belleğini hızlı biçimde sınıflandırmak için en yararlı yerleşik API'lerden biridir. Çıktıda `rss`, `heapTotal`, `heapUsed`, `external` ve `arrayBuffers` alanları bulunur. Bu değerler byte cinsindedir ve monitoring sırasında MiB veya byte olarak tutarlı biçimde normalize edilmelidir. Worker Threads kullanılıyorsa RSS process genelini, diğer bazı alanlar ise çağrının yapıldığı thread bağlamını temsil eder. Yüksek trafikli monitoring için yalnız RSS gerekiyorsa daha hızlı olan `process.memoryUsage.rss()` API'si de değerlendirilebilir.
import process from 'node:process';
const usage = process.memoryUsage();
const metrics = {
rssMiB: usage.rss / 1024 / 1024,
heapTotalMiB: usage.heapTotal / 1024 / 1024,
heapUsedMiB: usage.heapUsed / 1024 / 1024,
externalMiB: usage.external / 1024 / 1024,
arrayBuffersMiB: usage.arrayBuffers / 1024 / 1024,
};
console.log(metrics);
rss
RSS process'in fiziksel bellekte resident durumda bulunan toplam alanını ifade eder. JavaScript heap, C++ object'leri, code memory ve çeşitli native alanlar bu değere katkıda bulunabilir. Container memory limitine yaklaşmayı değerlendirirken RSS, heapUsed değerinden daha geniş bir görünüm sağlar. Ancak RSS tek başına hangi bileşenin büyüdüğünü söylemez. Alarm sonrası heapUsed, external, Buffer ve işletim sistemi seviyesindeki memory metrikleriyle birlikte incelenmelidir.
heapTotal
`heapTotal` V8 tarafından heap için ayrılmış mevcut alanın önemli kısmını gösterir. Bu değer gerçek canlı object miktarıyla aynı değildir çünkü V8 gelecekteki allocation'lar için kullanılmayan kapasite bulundurabilir. Trafik arttığında heapTotal büyüyebilir ve hemen işletim sistemine geri dönmeyebilir. HeapUsed ile heapTotal arasındaki fark kullanılabilir heap kapasitesi hakkında fikir verir. Yüksek heapTotal tek başına leak kanıtı olmadığından baseline ve GC sonrası davranış esas alınmalıdır.
heapUsed
`heapUsed` V8 heap üzerinde o anda kullanılan JavaScript memory miktarını gösterir. Object, array, closure ve benzeri managed allocation'lar bu değere yansır. Sağlıklı uygulamada trafik sırasında yükselip garbage collection sonrasında düşen bir yapı görmek normaldir. Leak durumunda GC sonrası minimum değerler zaman içinde sürekli yukarı kayabilir. Bu nedenle heapUsed grafiğine tek değer yerine uzun zaman penceresinde ve request rate ile birlikte bakılmalıdır.
external
`external` V8'in takip ettiği heap dışı belirli allocation'ların toplamını gösterir. Buffer yoğun işlerde bu alan hızlı büyüyebilir ve heapUsed normal görünmesine rağmen process RSS'ini yükseltebilir. Binary protocol, file processing veya compression servislerinde external memory için ayrı alarm yararlı olabilir. Değerin düşmemesi reference retention veya native kullanım sorununa işaret edebilir. Ancak root cause doğrulaması için allocation davranışı ve ilgili kütüphane ayrıca incelenmelidir.
arrayBuffers
`arrayBuffers` ArrayBuffer ve SharedArrayBuffer allocation'larını, ayrıca Node.js Buffer'larını kapsayan daha özel bir metriktir. Bu değer external içinde bulunduğu için iki metriği doğrudan toplayarak toplam memory hesaplamak double counting oluşturabilir. Büyük Buffer pool veya network payload senaryosunda arrayBuffers artışı güçlü bir teşhis sinyalidir. Heap snapshot bazı JavaScript retaining path'leri gösterebilse de underlying native allocation'ın tamamı aynı görünürlüğe sahip olmayabilir. Bu yüzden Buffer incident'ında RSS ve arrayBuffers korelasyonu özellikle izlenmelidir.
Hangi Metrik Hangi Problemi Gösterir?
HeapUsed büyüyorsa JavaScript object retention veya yüksek allocation rate ilk şüpheler arasındadır. HeapUsed sabitken external ve arrayBuffers yükseliyorsa Buffer veya ArrayBuffer kullanımı araştırılmalıdır. Heap ve external görece sabitken RSS artıyorsa native allocation veya allocator fragmentation ihtimali değerlendirilir. Container memory metriği yükselirken process RSS düşükse sidecar, tmpfs veya aynı pod içindeki diğer container'lar da kontrol edilmelidir. En güvenilir teşhis tek metric değil bu değerlerin trafik, GC ve deployment değişiklikleriyle birlikte okunmasıdır.
RSS ile Heap Used Arasındaki Fark
RSS ile heapUsed arasındaki ayrım Node.js memory incident'larının en temel konularından biridir. HeapUsed yalnız V8 tarafından yönetilen JavaScript heap'in kullanılan bölümünü gösterirken RSS process'in resident memory footprint'ini daha geniş biçimde kapsar. Bu nedenle 250 MB heapUsed gören bir process'in RSS değeri 500 MB veya daha yüksek olabilir. Aradaki fark otomatik olarak leak değildir çünkü native memory, code, Buffer ve allocator davranışı da sürece dahildir. Production alarmı tasarlarken iki metriği aynı anlama geliyormuş gibi kullanmamak gerekir.
RSS Neleri İçerir?
RSS process'in fiziksel bellekte bulunan sayfalarının toplamına yakın bir görünüm sağlar. V8 heap, native allocation'lar, code, shared library sayfaları ve başka runtime alanları bu değere katkıda bulunabilir. Worker thread'ler aynı process içinde bulunduğundan onların memory kullanımı da toplam RSS üzerinde etkili olur. RSS container limitine göre headroom hesaplamak için önemli bir metriktir. Yine de hangi component'in büyüdüğünü bulmak için RSS'in diğer memory metrikleriyle parçalanması gerekir.
Heap Used Neyi Gösterir?
HeapUsed yalnız V8 heap üzerindeki aktif managed memory miktarını ifade eder. JavaScript object graph leak'lerinde bu değer çoğu zaman belirgin bir trend gösterir. Buffer veya native addon leak'lerinde ise heapUsed çok az değişebilir. GC sonrasındaki heapUsed baseline'ı uzun süreli leak analizinde anlık maksimum değerden daha değerlidir. Uygulama sürümleri karşılaştırılırken aynı workload sonrasındaki heapUsed değerleri memory regression tespitinde kullanılabilir.
Heap Sabitken RSS Neden Büyüyebilir?
HeapUsed sabit kaldığı hâlde RSS artışı Buffer, native addon, allocator fragmentation veya worker kaynaklı olabilir. Linux sistemlerde glibc `malloc` fragmentation nedeniyle `heapTotal` sabit kalırken RSS'in uzun süre yüksek kalabildiği Node.js belgelerinde de belirtilir. Bu durum JavaScript heap snapshot karşılaştırmasında belirgin leak bulunamamasına yol açabilir. Böyle bir incident'ta external memory ve arrayBuffers ilk kontrol noktalarındandır. Bunlar da sabitse native profiler ve allocator davranışı incelenmelidir.
Native Memory
Native memory V8 heap grafiğine tam olarak yansımayan allocation'ları içerebilir. Database driver, compression library veya native addon kendi C/C++ heap alanını kullanabilir. Bu nedenle JavaScript snapshot temiz görünürken process sürekli büyümeye devam edebilir. Dependency isolation yaparak ilgili native paket kapalı ve açık durumdaki RSS trendleri karşılaştırılabilir. Sorun minimal reproduction ile doğrulanabiliyorsa package maintainer'a teknik bir issue açmak root cause çözümünü hızlandırır.
Buffer Kullanımı
Buffer Node.js uygulamalarında network ve dosya I/O için çok yaygındır. Büyük Buffer'ların collection içinde tutulması external memory ve RSS'i hızlı şekilde yükseltebilir. Tek seferlik büyük allocation GC sonrasında zamanla düşebilirken sürekli retained Buffer leak davranışı gösterir. Upload servislerinde request başına payload'ı RAM'e toplamak bu riski artırır. Stream tabanlı pipeline ve bounded queue kullanımı Buffer footprint'ini daha öngörülebilir tutar.
Allocator Fragmentation
Allocator fragmentation serbest bırakılmış alanın process içinde yeniden kullanılabilir kalmasına rağmen işletim sistemine kolayca geri dönmemesi durumudur. Sonuç olarak application object sayısı sabitlenirken RSS yüksek kalabilir. Linux ve glibc kullanan ortamlarda bu davranış özellikle incelenebilir. Fragmentation ile leak'i ayırmak için heapUsed, external, allocation workload ve uzun idle dönem sonrasındaki RSS birlikte gözlenmelidir. Allocator değiştirme gibi müdahaleler yalnız kontrollü benchmark ve operasyonel değerlendirme sonrasında yapılmalıdır.
Memory Leak ile Normal Bellek Büyümesi Arasındaki Fark
Production servisin memory grafiğinin yükselmesi tek başına leak bulunduğu anlamına gelmez. Uygulama başlangıçta module yükleyebilir, JIT optimizasyonu yapabilir, cache doldurabilir ve connection pool oluşturabilir. Bu warm-up sürecinden sonra memory belirli bir seviyede dengeleniyorsa davranış normal olabilir. Memory leak'te ise benzer trafik döngülerinden ve garbage collection'lardan sonra baseline sürekli yükselir. Normal growth ile leak'i ayırmak için yeterince uzun gözlem penceresi ve tekrarlanabilir workload gerekir.
Warm-Up Memory Growth
Node.js application ilk dakikalarda route module'lerini, lazy dependency'leri ve cache entry'lerini yükleyebilir. JIT optimizasyonları ve database pool bağlantıları da startup sonrası memory'nin yükselmesine yol açar. Bu artış belirli bir noktada plateau oluşturuyorsa tek başına problem değildir. Load test öncesinde yeterli warm-up süresi tanımlamak baseline ölçümünü daha güvenilir yapar. Memory regression testinde candidate ve baseline sürümler aynı warm-up prosedürünü izlemelidir.
Traffic-Dependent Growth
Trafik artarken concurrent request sayısı, Buffer miktarı ve active Promise state'i de geçici olarak artabilir. Bu nedenle peak trafik sırasında memory'nin yükselmesi doğal olabilir. Trafik düştükten ve GC döngüleri tamamlandıktan sonra baseline tekrar normal seviyeye yaklaşmalıdır. Request rate ile memory arasında geçici korelasyon olması leak kanıtı değildir. Trafik normalize edilmiş MB başına request gibi ölçümler kalıcı büyümeyi ayırt etmeye yardımcı olabilir.
Garbage Collection Sonrası Plateau
Sağlıklı uygulamada heapUsed test sırasında yükselir ve GC sonrasında daha düşük bir seviyeye iner. Birkaç döngü sonra minimum noktalar birbirine yakınsa stabil plateau oluşmuş olabilir. Cache warm-up nedeniyle ilk minimum ile sonraki minimum arasında belirli fark görülebilir. Önemli olan bu baseline'ın sonsuza kadar büyümemesidir. Soak test boyunca GC sonrası minimumları kaydetmek leak analizinde maksimum heap değerlerinden daha yararlı olabilir.
Leak Pattern'i
Leak pattern çoğu zaman test döngülerinde her GC sonrasında biraz daha yüksek heap baseline şeklinde görünür. Benzer request set'i tekrarlandıkça retained object sayısı artmaya devam eder. Listener count, queue length veya Map size gibi application metric'leri de aynı eğimi gösterebilir. Heap snapshot comparison hangi constructor'ların ve retaining path'lerin büyüdüğünü ortaya çıkarabilir. Leak doğrulandıktan sonra fix uygulanmalı ve aynı soak test birebir tekrar edilmelidir.
Memory Bloat
Memory bloat teknik olarak leak olmadan uygulamanın gereğinden fazla canlı veri tutması durumudur. Örneğin cache 500 bin entry ile sabitlenebilir ve artık büyümeyebilir, fakat bu cache gerçek ihtiyaç için aşırı büyük olabilir. GC bu nesneleri temizleyemez çünkü hâlâ bilinçli şekilde referenced durumdadır. Bloat latency ve container density üzerinde ciddi maliyet oluşturabilir. Çözüm leak bulmak değil cache limitlerini, veri yapısını ve business requirement'ı yeniden tasarlamaktır.
Memory Fragmentation
Fragmentation memory'nin teorik olarak serbest bırakılmış olmasına rağmen process RSS değerinin yüksek kalmasına yol açabilir. Özellikle farklı boyutlarda yoğun native allocation yapan workload'larda allocator davranışı önem kazanır. Heap snapshot bu problemi JavaScript object leak gibi göstermeyebilir. Uzun idle dönem, external memory trendi ve native profiler sonuçları birlikte değerlendirilmelidir. Fragmentation teşhisi yapılmadan heap limitini veya cache boyutunu değiştirmek yanlış optimizasyon olabilir.
V8 Heap Nasıl Çalışır?
V8 heap bütün JavaScript nesnelerini tek homojen memory alanında tutmaz. Nesnelerin yaşı, boyutu ve runtime amacı doğrultusunda farklı heap space'leri kullanılır. Kısa ömürlü object'ler genellikle young generation içinde başlar ve yaşamaya devam edenler daha uzun ömürlü alanlara taşınabilir. Bu generational yaklaşım kısa ömürlü allocation'ların hızlı biçimde temizlenmesini sağlar. Node.js heap memory garbage collection ve V8 bellek ayarları nasıl optimize edilir sorusunun doğru cevabı, önce uygulamanın allocation profile'ını ölçmek ve sonra runtime limitlerini workload'a göre belirlemektir.
Young Generation
Young generation yeni oluşturulan ve kısa süre yaşayacağı varsayılan nesneler için kullanılır. Web request sırasında oluşturulan geçici DTO, array veya intermediate object'lerin önemli bölümü bu kategoride olabilir. Young generation collection'ları old generation collection'larına göre genellikle daha sık ve daha kısa sürer. Allocation rate çok yüksekse minor GC sıklığı artabilir. Gereksiz object copy ve büyük geçici array üretimini azaltmak bu baskıyı düşürebilir.
New Space
New Space kısa ömürlü yeni object'lerin yer aldığı genç nesil alanıdır. Bir request sırasında oluşturulup hemen kullanımdan çıkan birçok object burada başlayabilir. Sık allocation yapılması New Space üzerinde yüksek churn oluşturur ve minor GC ihtiyacını artırır. Bu durum her zaman kötü değildir çünkü generational GC tam olarak kısa ömürlü nesneleri verimli temizlemek için tasarlanmıştır. Problem allocation hızı latency hedeflerini etkileyecek kadar GC baskısı oluşturduğunda ortaya çıkar.
Semi-Space
Young generation yönetiminde semi-space yapıları nesnelerin collection sırasında bir alandan diğerine taşınmasına yardımcı olur. Hayatta kalan object'ler copy edilerek yeni alanda tutulur ve artık erişilemeyenler geride bırakılır. Çok sayıda object birkaç collection boyunca yaşamaya devam ederse promotion miktarı artabilir. Semi-space ayarlarını rastgele değiştirmek yerine GC logları ve allocation profili incelenmelidir. Runtime flag tuning uygulama seviyesindeki gereksiz retention sorunlarının yerine geçmez.
Old Generation
Old generation daha uzun süre yaşayan object'lerin tutulduğu alandır. Cache entry'leri, module-level state ve uzun ömürlü application graph çoğunlukla burada kalabilir. Old generation dolmaya yaklaştığında major GC maliyeti daha görünür hâle gelir. Memory leak old space baseline'ının sürekli büyümesine neden olabilir. Heap limitine yaklaşan uygulamada daha sık major collection ve daha yüksek latency görmek olasıdır.
Large Object Space
Büyük object'ler V8 tarafından ayrı space politikalarıyla ele alınabilir. Çok büyük array veya tek seferde oluşturulan dev JSON yapıları heap üzerinde ciddi allocation spike oluşturur. Bu nesnelerin copy veya compaction davranışı küçük object'lerle aynı maliyet profilini taşımayabilir. Büyük JSON response veya report üretimi bu nedenle memory benchmark gerektirir. Veriyi page, batch veya stream biçiminde işlemek peak heap kullanımını düşürür.
Code Space
Code Space V8'in çalıştırılabilir kod ve ilgili runtime yapılarını yönettiği alanlardan biridir. Application warm-up sırasında optimized code üretimi memory profilini değiştirebilir. Bu artış kullanıcı verisi leak'i ile aynı şekilde yorumlanmamalıdır. `v8.getHeapCodeStatistics()` code ve metadata miktarını ayrı gözlemlemek için yararlı olabilir. Çok sıra dışı code memory büyümesi dynamic code generation veya runtime davranışı açısından ayrıca araştırılmalıdır.
Nesnelerin Old Space'e Promotion Süreci
Young generation collection'larından sağ çıkan nesneler belirli koşullarda old generation'a taşınır. Normal uzun ömürlü application state için bu beklenen davranıştır. Sorun request'e ait geçici object'lerin yanlış referans nedeniyle tekrar tekrar hayatta kalması ve old space'e promotion almasıdır. Bu durumda request başına küçük retention zaman içinde büyük heap kullanımına dönüşebilir. Allocation timeline ve heap snapshot retaining path analizi hangi nesnelerin neden uzun ömürlü hâle geldiğini gösterebilir.
V8 Garbage Collection Nasıl Çalışır?
V8 garbage collector kısa ve uzun ömürlü nesnelerin farklı davranışlarından yararlanarak bellek geri kazanımı yapar. Generational model sayesinde genç nesilde sık ve daha küçük collection'lar, old generation tarafında ise daha kapsamlı collection süreçleri yürütülebilir. Modern V8 bazı marking ve cleanup işlerini incremental veya concurrent biçimde yaparak ana thread üzerindeki pause etkisini azaltmaya çalışır. Buna rağmen yüksek allocation rate veya heap pressure application latency'sini etkileyebilir. GC'yi tamamen ortadan kaldırmak yerine allocation miktarını ve canlı object set'ini yönetmek daha gerçekçi bir production hedefidir.
Generational Garbage Collection
Generational GC çoğu object'in kısa süre yaşadığı gözleminden yararlanır. Yeni nesneler young generation içinde başlar ve hayatta kalanlar zamanla old generation'a taşınabilir. Böylece bütün heap'i her seferinde taramak yerine daha küçük alanlarda sık collection yapılabilir. Uygulama sürekli büyük ve uzun ömürlü object üretiyorsa bu avantaj azalabilir. Cache ve queue gibi yapıları bounded tutmak old generation baskısını kontrol altında tutar.
Minor GC
Minor GC ağırlıklı olarak young generation üzerinde çalışır. Çok sayıda kısa ömürlü allocation yapan API'lerde bu collection'lar sık görülebilir. Tek tek pause süreleri küçük olsa bile aşırı sıklık toplam CPU maliyetini yükseltebilir. Allocation profiler hangi kod yollarının gereksiz object churn oluşturduğunu gösterebilir. Object pooling her durumda gerekli değildir ve yanlış uygulanırsa daha uzun object lifetime oluşturarak ters etki yaratabilir.
Major GC
Major GC old generation gibi daha geniş heap alanlarıyla ilgilenir. Heap büyüdükçe bu süreçlerin toplam maliyeti ve latency etkisi daha önemli olabilir. Frequent major GC uygulamanın canlı object set'inin heap limitine göre fazla olduğuna işaret edebilir. Heap limitini yükseltmek major GC sıklığını azaltabilir fakat her collection'ın daha büyük alanla çalışmasına da yol açabilir. En doğru ayar benchmark ve production telemetry ile belirlenmelidir.
Marking
Marking aşamasında garbage collector root'lardan erişilebilen object graph'ını belirler. Bir object Map, closure veya listener üzerinden hâlâ reachable ise live olarak işaretlenir. Bu nedenle leak teşhisinde retaining path kavramı önemlidir. Büyük bir object'i doğrudan kaldırmak yerine onu hayatta tutan küçük closure'ı veya listener'ı temizlemek gerekebilir. Heap snapshot Retainers görünümü bu ilişkiyi anlamak için güçlü bir araçtır.
Sweeping
Sweeping artık canlı olmadığı belirlenen alanların yeniden allocation için kullanılabilir hâle getirilmesidir. Serbest bırakılan V8 memory'nin tamamının hemen process RSS üzerinden işletim sistemine dönmesi beklenmemelidir. Runtime gelecekteki allocation'lar için bazı alanları tutabilir. Bu nedenle GC gerçekleştiği hâlde RSS'in aynı seviyede kalması tek başına leak göstergesi değildir. HeapUsed ve live object baseline'ı daha anlamlı karşılaştırma sağlar.
Compaction
Compaction canlı object'leri daha düzenli alanlara taşıyarak heap içi fragmentation'ı azaltmaya yardımcı olur. Büyük heap üzerinde compaction maliyeti CPU ve pause süresine katkıda bulunabilir. Heap limitine yakın çalışma garbage collector'ın daha fazla efor harcamasına neden olur. Memory budget bu nedenle heap'i container limitinin son megabaytına kadar dolduracak şekilde tasarlanmamalıdır. Native ve Buffer alanları için ayrıca headroom bırakılmalıdır.
Incremental ve Concurrent GC
V8 garbage collection işlerinin bir bölümünü küçük parçalara ayırarak veya ana JavaScript execution ile eş zamanlı farklı işçilerde yürütebilir. Bu yaklaşım uzun stop sürelerini azaltmaya yardımcı olur. Buna rağmen GC CPU tüketir ve yüksek pressure altında application throughput'unu etkileyebilir. Event loop lag ve GC duration metriklerinin aynı panelde tutulması korelasyonu görmeyi kolaylaştırır. Runtime tuning yapmadan önce application allocation davranışı ölçülmelidir.
Garbage Collection Node.js Performansını Nasıl Etkiler?
Garbage collection uygulama için ücretsiz bir işlem değildir. Collector canlı object graph'ını analiz ederken CPU tüketir ve bazı aşamalarda JavaScript execution kısa süre durabilir. Bu pause süreleri düşük trafik altında fark edilmese bile yüksek concurrency ve düşük latency hedeflerinde P99 değerlerini etkileyebilir. Heap ne kadar baskı altındaysa collection sıklığı da o kadar artabilir. Memory optimization bu nedenle yalnız OOM engelleme değil latency ve throughput dengesini koruma çalışmasıdır.
GC Pause
GC pause JavaScript execution'ın collector çalışması nedeniyle belirli süre ilerleyemediği dönemleri ifade eder. Modern V8 pause etkisini azaltmak için çeşitli concurrent teknikler kullanır fakat tamamen ortadan kaldırmaz. Uzun pause sırasında request handler'lar cevap üretemez ve timer'lar gecikebilir. P99 latency spike'ları GC event'leriyle zaman olarak karşılaştırılmalıdır. Birkaç kısa pause normal olabilir, sürekli uzun pause ise heap pressure veya aşırı allocation sinyalidir.
Event Loop Stall
Node.js request handler'larının ana JavaScript thread'i üzerinde çalışması event loop stall etkisini önemli hâle getirir. GC dışında synchronous CPU işi de benzer stall yaratabilir. Bu nedenle yalnız event loop lag grafiğine bakarak GC suçlanmamalıdır. GC duration, CPU profile ve request latency birlikte incelenmelidir. Eğer lag allocation spike ile aynı anda artıyorsa memory davranışı güçlü aday hâline gelir.
P95 ve P99 Latency
Average latency GC kaynaklı kısa tail spike'larını gizleyebilir. P95 ve özellikle P99 kullanıcıların en yavaş deneyimlerini daha görünür kılar. Major GC dönemlerinde tail latency yükselirken ortalama değer kabul edilebilir kalabilir. Memory dashboard'a request latency paneli eklemek bu nedenle önemlidir. Heap tuning yalnız throughput artışına göre değil SLO içindeki tail latency sonucuna göre değerlendirilmelidir.
Allocation Rate
Allocation rate uygulamanın birim zamanda ne kadar yeni memory oluşturduğunu ifade eder. Çok yüksek rate young generation collection'larını sıklaştırabilir. Büyük array kopyaları, `JSON.parse`, `JSON.stringify` ve gereksiz object spread işlemleri bu oranı artırabilir. Heap profile veya allocation sampling hangi function'ların allocation hotspot olduğunu gösterebilir. Kod optimizasyonu canlı object sayısını değil yalnız geçici allocation'ı azaltarak bile GC CPU maliyetini düşürebilir.
Heap Pressure
Heap pressure V8'in mevcut heap kapasitesine göre yüksek memory kullanımı altında çalışmasını ifade eder. Limit yaklaştıkça collector kullanılmayan alan bulmak için daha sık çalışabilir. Eğer live object set gerçekten çok büyükse collection sonrasında yeterli alan açılamaz. Bu durum sonunda JavaScript heap out of memory hatasına kadar ilerleyebilir. Memory budget ve bounded data structure'lar heap pressure'ın sürekli yüksek kalmasını önlemeye yardımcı olur.
Throughput vs Memory Trade-Off
Daha büyük heap bazı workload'larda collection sıklığını azaltarak throughput'u artırabilir. Buna karşılık daha büyük canlı heap collection sırasında daha fazla çalışma gerektirebilir ve container başına process yoğunluğunu azaltır. Çok küçük heap ise sık GC nedeniyle CPU tüketimini artırabilir. Bu nedenle ideal değer “mümkün olan en büyük heap” değildir. Gerçek production benzeri benchmark ile throughput, P99 latency, RSS ve GC süresi birlikte ölçülmelidir.
Node.js Memory Leak Nedir?
Node.js memory leak uygulamanın artık business açısından ihtiyaç duymadığı belleğin hâlâ reachable referanslar nedeniyle garbage collector tarafından geri kazanılamaması durumudur. Leak çoğu zaman küçük bir collection veya listener ile başlar ve uzun uptime boyunca büyür. `Node.js memory leak nasıl tespit edilir ve çözülür` sorusunun cevabı yalnız heap snapshot almak değildir; önce growth pattern doğrulanmalı, sonra retaining path bulunmalı ve fix aynı workload ile test edilmelidir. Bir object'in boyutu kadar onu hayatta tuttuğu object graph da önemlidir. Production teşhisinde shallow size ve retained size ayrımı bu nedenle sık kullanılır.
Reachable Object Kavramı
Reachable object GC root'lardan başlayan bir referans zinciri üzerinden erişilebilen nesnedir. Uygulama bu object'i artık kullanmıyor olsa bile reference kaldığı sürece collector bunu güvenli şekilde silemez. Global Map, event listener veya closure sık karşılaşılan retaining kaynaklarıdır. Leak çözümü object'i “delete etmeye çalışmak” değil yaşam süresini gereksiz uzatan referansı kaldırmaktır. Heap snapshot Retainers paneli bu zinciri adım adım incelemeyi sağlar.
GC Root Nedir?
GC root garbage collector'ın object graph taramasına başladığı temel erişim noktalarını ifade eder. Global state, aktif execution context veya runtime tarafından tutulan çeşitli referanslar root zincirinin parçası olabilir. Bir leak object'i çoğu zaman doğrudan root değildir, fakat root'a kadar uzanan retaining path üzerinden yaşamaya devam eder. Heap analysis sırasında “bu object neden silinmedi?” sorusunun cevabı root'a kadar takip edilir. Bu bakış yalnız constructor sayısına bakmaktan daha güvenilir teşhis sağlar.
Retaining Path
Retaining path bir object'i GC root'a bağlayan referans zinciridir. Örneğin global singleton içindeki Map bir session object'ini, session object'i de büyük bir request payload'ını tutabilir. En büyük object'i temizlemek yerine Map entry lifecycle'ını düzeltmek kalıcı çözüm olur. Heap snapshot tool'ları retainers görünümünde bu zinciri incelemeye yardımcı olur. Aynı retaining path'in snapshot'lar arasında büyümesi leak hipotezini güçlendirir.
Shallow Size
Shallow size yalnız ilgili object'in doğrudan kapladığı belleği ifade eder. Küçük bir closure veya Map entry shallow size olarak önemsiz görünebilir. Ancak bu küçük object büyük bir graph'ı referans ediyorsa gerçek impact çok daha yüksek olur. Bu nedenle heap summary ekranını sadece shallow size'a göre sıralamak leak'i kaçırabilir. Retained size ve retaining path birlikte incelenmelidir.
Retained Size
Retained size ilgili object ortadan kalktığında onunla birlikte erişilemez hâle gelecek toplam bellek miktarını ifade eder. Küçük bir cache object milyonlarca entry'yi tuttuğunda retained size çok büyük olabilir. Leak root'larını bulmak için retained size güçlü bir önceliklendirme sinyalidir. Yine de büyük retained size her zaman bug değildir çünkü application'ın ana state graph'ı doğal olarak büyük olabilir. Snapshot comparison büyümenin zaman içindeki yönünü göstererek bu ayrımı kolaylaştırır.
Leak'in Temel Nedeni: Gereksiz Referansın Yaşamaya Devam Etmesi
JavaScript memory leak'lerinin ortak noktası ihtiyaç kalmayan veriye referansın sürmesidir. Cache entry silinmez, listener kaldırılmaz, timer kapanmaz veya pending operation context'i bırakmaz. Garbage collector bu nesnelerin business açısından gereksiz olduğunu anlayamaz. Bu nedenle resource lifecycle kod tasarımının bir parçası olmalıdır. Her acquire işleminin bir release veya bounded lifetime karşılığı bulunması memory güvenliğini ciddi biçimde artırır.
Node.js'te En Sık Görülen Memory Leak Nedenleri
Production Node.js servislerinde leak nedenleri genellikle birkaç tekrar eden pattern etrafında toplanır. Sınırsız cache, temizlenmeyen EventEmitter listener'ı, timer, closure ve global collection en yaygın örneklerdir. Database connection veya WebSocket state'i gibi resource'lar da lifecycle hatalarında memory ve handle leak oluşturabilir. Native addon kullanılıyorsa JavaScript heap dışında ayrı leak ihtimali vardır. Code review checklist'in bu pattern'leri doğrudan sorgulaması leak riskini incident oluşmadan azaltabilir.
Unbounded Cache
Sınırsız cache her benzersiz key için yeni entry ekler fakat hiçbir zaman eviction yapmaz. Trafik ve kullanıcı sayısı arttıkça memory de aynı yönde büyür. GC bu entry'leri silemez çünkü Map veya object hâlâ referans tutar. TTL, maximum entry veya maximum byte sınırı eklemek temel çözümdür. Verinin process yaşam süresinden uzun veya replica'lar arasında ortak olması gerekiyorsa external cache tercih edilebilir.
EventEmitter Listener
Her request için shared EventEmitter üzerine yeni listener eklemek ve kaldırmamak zamanla listener sayısını artırır. Listener callback closure üzerinden request state'ini de hayatta tutabilir. Node.js default olarak aynı event için yüksek listener sayısında `MaxListenersExceededWarning` üretir. Bu warning hard limit değildir ve yalnız limiti artırmak leak'i çözmez. Listener'ın hangi lifecycle sonunda kaldırılacağı açık biçimde tanımlanmalıdır.
Closure
Closure ihtiyaç duyduğundan daha geniş bir lexical scope'u referans ederek büyük object'leri beklenenden uzun tutabilir. Özellikle async callback veya timer içinde request body'yi dolaylı biçimde capture etmek risklidir. Küçük bir callback'in retained size değeri bu nedenle çok büyük olabilir. Yalnız gerekli primitive değerleri ayrı değişkene almak object lifetime'ını kısaltabilir. Heap snapshot Retainers görünümü closure kaynaklı leak'i ortaya çıkarmada oldukça faydalıdır.
Global Variable
Global değişkenler process yaşamı boyunca erişilebilir kalmaya eğilimlidir. Request verisini global array veya object içine eklemek GC için kalıcı referans oluşturabilir. Singleton servis de davranış açısından global state'e benzer risk taşıyabilir. Global state yalnız configuration veya bounded application metadata gibi kontrollü veriler için kullanılmalıdır. Kullanıcı ve request verisi yaşam süresi açık store'larda tutulmalıdır.
Timer
`setInterval` callback'i temizlenmediği sürece timer ve onun closure referansları yaşamaya devam edebilir. Per request interval oluşturmak özellikle risklidir. Request tamamlandığında interval hâlâ aktifse request state'i bellekte tutulabilir. `clearInterval` ve `clearTimeout` cleanup contract'ın parçası olmalıdır. Uzun ömürlü service timer'larında da shutdown sırasında cleanup yapılması gerekir.
Unresolved Promise
Uzun süre resolve olmayan asynchronous operation closure içindeki state'i beklenenden uzun süre tutabilir. Tek pending Promise her zaman leak değildir fakat sınırsız sayıda operation birikiyorsa memory problemi oluşur. Timeout ve cancellation mekanizması olmadan remote dependency failure bu birikimi büyütebilir. `AbortController` destekleyen API'lerde request deadline ile cancellation bağlamak faydalıdır. Pending operation count production metriği olarak izlenebilir.
Database Connection
Pool'dan alınan connection error path'te release edilmezse connection leak oluşabilir. Pool dolduğunda yeni request'ler queue'da beklemeye başlar ve pending state memory kullanımını artırabilir. `try` ve `finally` ile release contract net tutulmalıdır. Query sonucunun aşırı büyük olması connection leak olmasa bile heap spike yaratabilir. Pool size, wait queue ve query result size birlikte izlenmelidir.
WebSocket
WebSocket connection uzun ömürlü olduğu için socket state ve listener'lar saatlerce bellekte kalabilir. Disconnect olduğunda room membership, timer ve message queue temizlenmezse gerçek leak oluşur. Slow consumer için sınırsız outbound queue ayrıca RSS büyümesine yol açabilir. Heartbeat ve connection cleanup lifecycle'ın zorunlu parçalarıdır. Connection başına memory miktarı load testte ölçülmeli ve capacity plan buna göre yapılmalıdır.
Büyük Queue
In-memory queue producer consumer'dan hızlı olduğunda sınırsız büyüyebilir. Her job payload ve closure referansı memory üzerinde kalır. Bu durum klasik leak olmasa bile aynı sonucu, yani OOM riskini üretir. Maximum queue depth ve load shedding policy belirlenmelidir. Dayanıklı veya yüksek hacimli işlerde external queue kullanımı process memory budget'ını korur.
Native Addon
Native addon C veya C++ tarafında allocation yapıp release etmeyi unutursa V8 heap normal kalırken RSS büyüyebilir. JavaScript heap snapshot bu problemi doğrudan göstermeyebilir. Dependency version bisect ve addon kapalı test root cause'u daraltır. Native profiler veya allocator tracing gerekebilir. Minimal reproduction hazırlanması hem kendi teşhisinizi hem upstream issue sürecini hızlandırır.
Unbounded Cache Memory Leak'i
Unbounded cache kurumsal Node.js servislerinde en kolay oluşturulan memory problemlerinden biridir. Bir Map'e request başına veri eklemek ilk günlerde hızlı ve basit görünür. Ancak key cardinality üretim trafiğinde tahmin edilenden çok daha yüksek olabilir. Cache entry'leri reference tuttuğu için garbage collector bunları silemez. Her in-memory cache tasarımında maksimum boyut, TTL, eviction davranışı ve hit ratio ölçümü birlikte tanımlanmalıdır.
Map
`Map` cache implementasyonu için kullanışlıdır fakat kendiliğinden entry silmez. Benzersiz user veya request ID key olarak ekleniyorsa collection sürekli büyüyebilir. `map.size` metriğini monitoring'e taşımak kolay bir koruma sağlar. Maximum entry veya LRU policy uygulanmalıdır. Cache lifecycle belirsizse Map kullanımı yerine hazır bounded abstraction tercih etmek daha güvenlidir.
Set
`Set` yalnız değer tutar ancak aynı unbounded growth riski burada da vardır. Seen ID veya processed event listesi sonsuza kadar saklanırsa uzun uptime boyunca memory artar. TTL gereksinimi varsa plain Set tek başına yeterli abstraction değildir. Event ID deduplication için zaman penceresi veya external store düşünülebilir. Set size production metric olarak takip edilmelidir.
Plain Object
Plain object key value store olarak kullanıldığında da bounded davranış otomatik oluşmaz. Dynamic key'ler sonsuza kadar object üzerinde kalabilir. Prototype behavior ve key normalization gibi ek sorunlar da ortaya çıkabilir. Cache amacıyla Map çoğu zaman semantics açısından daha açıktır ancak yine limit gerekir. Data structure seçimi memory lifecycle requirement'ını ortadan kaldırmaz.
Request Başına Yeni Cache Entry
Request ID gibi neredeyse her çağrıda benzersiz bir değeri cache key yapmak hit ratio'yu düşürür ve growth rate'i yükseltir. Böyle bir cache aslında cache değil memory archive gibi davranabilir. Entry başına yalnız birkaç kilobyte olsa bile milyonlarca request sonunda büyük footprint oluşur. Key cardinality metric ve eviction count tasarım aşamasında belirlenmelidir. Soak test gerçekçi benzersiz key dağılımı kullanmalıdır.
TTL Olmamasının Riski
TTL eski veya artık yararlı olmayan entry'lerin zaman içinde silinmesini sağlar. TTL olmadan entry yalnız manuel delete veya process restart ile kaybolabilir. Bununla birlikte yalnız TTL kullanmak peak entry sayısını garanti etmez. Çok yüksek trafik kısa TTL penceresinde bile milyonlarca entry oluşturabilir. Bu nedenle TTL genellikle size limit ile birlikte kullanılmalıdır.
Size Limit Olmamasının Riski
Maximum entry veya byte sınırı yoksa cache traffic spike sırasında container memory'nin tamamını tüketebilir. TTL bu spike gerçekleşmeden önce devreye girmeyebilir. Bounded cache dolduğunda hangi entry'nin çıkarılacağı eviction policy ile belirlenir. Cache miss artışı kabul edilebilir olmalı ve downstream sistem kapasitesi buna göre planlanmalıdır. Memory güvenliği cache hit oranından daha yüksek önceliğe sahip olmalıdır.
Güvenli In-Memory Cache Nasıl Tasarlanır?
Güvenli in-memory cache process'in bellek bütçesini aşamayacak biçimde sınırlandırılmış olmalıdır. Sadece entry sayısı değil entry'lerin boyutu çok değişiyorsa byte bazlı limit de düşünülmelidir. TTL stale data'yı temizlerken LRU veya LFU gibi eviction politikaları kapasite dolduğunda hangi verinin çıkarılacağını belirler. Cache hit, miss, eviction ve size metrikleri production'da görünür olmalıdır. Cache business state'in tek kaynağı hâline gelmemeli ve process restart sonrasında kaybolabileceği kabul edilmelidir.
Maximum Entry Count
Maximum entry count cache'in en fazla kaç key tutabileceğini sınırlar. Entry boyutları birbirine yakınsa basit ve etkili bir korumadır. Limit production trafik cardinality ve memory benchmark sonucuna göre seçilmelidir. Limit dolduğunda yeni entry reddetmek veya eski entry çıkarmak üzere açık policy gerekir. Cache size metriği limite yaklaşırken alarm üretebilir.
Maximum Byte Size
Entry boyutları birkaç byte ile megabyte arasında değişiyorsa yalnız count limiti yetersiz kalır. Maximum byte size daha gerçekçi bir memory budget sunabilir. Object'in gerçek memory footprint'ini kesin ölçmek kolay olmadığı için serialized size veya application-specific weight kullanılabilir. Büyük entry'ler cache dışında bırakılabilir. Weight hesaplama maliyeti de benchmark edilmelidir.
TTL
TTL entry'nin belirli süre sonra stale kabul edilmesini sağlar. User profile gibi sık değişen data için kısa, reference data için daha uzun süre uygun olabilir. TTL business freshness requirement'a göre belirlenmelidir. Bütün entry'lerin aynı anda expire olması downstream sistemde stampede oluşturabilir. Jitter veya request coalescing gibi yöntemler bu riski azaltabilir.
LRU
LRU yakın zamanda kullanılmayan entry'leri eviction için önceliklendirir. Temporal locality bulunan workload'larda yüksek hit ratio sağlayabilir. Liste ve Map gibi ek metadata memory overhead'i getirir. Bu nedenle library seçerken sadece algorithm değil toplam footprint ölçülmelidir. Cache workload'u sürekli scan şeklindeyse LRU beklenen faydayı vermeyebilir.
LFU
LFU en sık kullanılan entry'leri korumaya çalışır. Uzun dönem popülerliği belirgin olan workload'larda avantaj sağlayabilir. Frequency metadata ek memory ve computation maliyeti oluşturur. Yeni ama kısa sürede popüler olacak entry'lerin davranışı implementation'a göre değişebilir. Algorithm seçimi gerçek access distribution benchmark'ıyla yapılmalıdır.
Eviction
Eviction cache capacity veya TTL policy nedeniyle entry'nin çıkarılmasıdır. Eviction rate çok yükselirse cache boyutu veya key strategy yeniden değerlendirilmelidir. Eviction sırasında resource cleanup gerekiyorsa callback güvenli şekilde çalışmalıdır. Cache'den çıkarılan object başka reference tarafından tutuluyorsa memory hemen düşmeyebilir. Heap snapshot retaining path bu durumda gerçek owner'ı gösterebilir.
Cache Metrics
Cache size, hit, miss, eviction ve load duration temel metriklerdir. Maximum capacity yüzdesi memory riskini erkenden gösterir. High-cardinality cache key metrik label olarak kullanılmamalıdır. Hit ratio tek başına başarılı cache anlamına gelmez çünkü yüksek hit ratio karşılığında aşırı memory kullanılıyor olabilir. Memory cost başına hit faydası capacity planning içinde değerlendirilmelidir.
Redis'e Taşınması Gereken Durumlar
Cache'in birden fazla replica arasında paylaşılması gerekiyorsa process-local memory uygun olmayabilir. Çok büyük data set veya restart sonrası korunması gereken cache de external store için adaydır. External cache network latency getirir ve yeni failure mode oluşturur. Buna rağmen application heap'inin kullanıcı sayısıyla sınırsız büyümesini engelleyebilir. Mimari karar latency, consistency ve memory budget birlikte değerlendirilerek verilmelidir.
WeakMap ve WeakSet Ne Zaman Kullanılmalı?
WeakMap ve WeakSet object lifetime ile bağlantılı metadata tutmak için yararlı yapılardır. Ana key object başka yerde reachable değilse weak collection onun tek başına yaşamaya devam etmesini engellemez. Bu özellik bazı memoization ve object metadata senaryolarında leak riskini azaltabilir. Ancak key enumeration ve primitive key ihtiyaçları nedeniyle genel amaçlı cache'in yerine geçmez. Weak reference davranışına business correctness bağlamak doğru değildir çünkü garbage collection zamanı deterministik değildir.
Weak Reference Nedir?
Weak reference bir object'in yalnız bu referans nedeniyle garbage collector tarafından canlı kabul edilmemesini sağlar. Object başka güçlü referanslar tarafından tutulmuyorsa collector uygun zamanda temizleyebilir. Bu davranış cache entry'nin kesin bir anda silineceği garantisini vermez. Dolayısıyla expiration veya business lifecycle için weak reference kullanılmamalıdır. Kullanım amacı memory ownership'i gerçek object lifetime'a bağlamak olmalıdır.
Map ile WeakMap Arasındaki Fark
Map key'lerine güçlü referans tutar ve entry delete edilene kadar key object'in yaşamasına katkıda bulunur. WeakMap ise uygun object key'leri zayıf biçimde tutar. WeakMap üzerinde normal Map gibi tüm key'leri enumerate etmek mümkün değildir. Bu nedenle size metriği veya LRU eviction gereken cache'lerde kullanılamaz. Object'e bağlı private metadata için ise temiz bir seçenek olabilir.
Object-Lifetime-Bound Cache
Bir parsed object için hesaplanan metadata yalnız object yaşadığı sürece gerekli olabilir. WeakMap bu ilişkiyi explicit cleanup yazmadan object lifetime'a bağlayabilir. Object GC olduğunda cache metadata'sı da tutulmaya devam etmez. Bu pattern request object veya AST node metadata gibi senaryolarda kullanılabilir. Yine de cached value key object'i başka bir yoldan tekrar referans ediyorsa beklenen cleanup gerçekleşmeyebilir.
WeakMap'in Kullanılamayacağı Cache Senaryoları
String user ID veya URL gibi primitive key kullanan genel cache için WeakMap uygun değildir. Cache size ölçmek ve en eski entry'yi çıkarmak gerektiğinde de enumeration eksikliği problem olur. TTL kontrollü business cache için deterministic eviction gerekir. Replica paylaşımı gerektiren data zaten process-local WeakMap ile çözülmemelidir. Bu nedenle WeakMap her memory leak probleminin otomatik çözümü değildir.
WeakRef Kullanımında Dikkat Edilecek Noktalar
WeakRef bir object'e garbage collector tarafından korunmayan erişim imkânı sunar. Object'in ne zaman collection'a uğrayacağı tahmin edilemez. Business logic “object hâlâ var mı?” sonucuna güveniyorsa race ve nondeterministic davranış ortaya çıkabilir. WeakRef daha çok memory-sensitive cache veya diagnostic amaçlarda dikkatle kullanılmalıdır. Çoğu application cache için bounded güçlü referanslar daha anlaşılır ve test edilebilir bir model sunar.
EventEmitter Memory Leak Nasıl Oluşur?
EventEmitter leak genellikle uzun ömürlü emitter üzerine kısa ömürlü request veya connection için listener eklenip kaldırılmadığında oluşur. Listener function closure üzerinden request state'i tutabilir. Emitter process boyunca yaşadığı için callback ve ona bağlı object graph da reachable kalır. Node.js yüksek listener sayısında warning üretse de bu yalnız erken uyarıdır. Kalıcı çözüm listener lifecycle'ını açıkça tanımlamak ve cleanup path'lerini test etmektir.
Listener'ın Reference Tutması
EventEmitter listener function'a güçlü referans tutar. Function lexical scope içindeki object'lere de erişiyorsa bu object'ler listener yaşamı boyunca tutulabilir. Küçük görünen callback bu nedenle büyük retained graph oluşturabilir. Heap snapshot'ta listener function üzerinden request veya session object'ine giden path görülebilir. Cleanup yapıldığında emitter reference'ı kaldırılır ve diğer referans yoksa graph GC için uygun hâle gelir.
Request İçinde Listener Eklemek
Shared emitter'a her HTTP request'te yeni listener eklemek yüksek riskli pattern'dir. Request bittiğinde listener otomatik kaldırılmaz. Trafik arttıkça listener count request sayısıyla birlikte büyüyebilir. Eğer gerçekten request bazlı subscription gerekiyorsa completion, close veya abort event'inde cleanup yapılmalıdır. Çoğu durumda request bazlı global subscription yerine Promise veya scoped callback tasarımı daha sade olabilir.
Listener Cleanup Yapmamak
Listener cleanup olmadığında object graph'ın hangi kısmının retained kaldığı zamanla büyüyebilir. Birkaç listener development ortamında fark edilmezken günler süren uptime sonunda binlerce listener oluşabilir. Warning limitini artırmak yalnız semptomu gizler. `listenerCount()` metric veya debug log olarak belirli kritik emitter'larda izlenebilir. Unit test start ve stop sonrası listener sayısının başlangıç değerine döndüğünü doğrulayabilir.
MaxListenersExceededWarning
Node.js aynı EventEmitter event'i için varsayılan olarak belirli sayının üzerindeki listener'larda olası memory leak warning'i üretir. Güncel default sınır 10 listener'dır ancak bu hard limit değildir ve emitter daha fazla listener kabul etmeye devam eder. Warning doğrudan leak kanıtı da değildir çünkü bazı meşru tasarımlar çok listener kullanabilir. Buna rağmen uyarıyı susturmadan önce neden bu kadar listener bulunduğu araştırılmalıdır. `setMaxListeners` ancak architecture gereksinimi gerçekten doğrulandıktan sonra değiştirilmelidir.
listenerCount()
`listenerCount()` belirli event için mevcut listener sayısını görmeye yardımcı olur. Soak test sırasında listener sayısı trafikle sürekli yükseliyorsa güçlü leak sinyali oluşur. Stable connection sayısıyla birlikte listener count da stabil kalmalıdır. Production metric olarak her event name'i label yapmak cardinality yaratabileceği için yalnız kritik emitter'lar seçilmelidir. Debug endpoint kullanılıyorsa authorization ve internal access sınırı uygulanmalıdır.
--trace-warnings
`--trace-warnings` Node.js warning'leri için stack trace göstererek listener'ın nerede eklendiğini bulmayı kolaylaştırabilir. MaxListenersExceededWarning ortaya çıktığında registration call site bu sayede görülebilir. Flag development veya staging teşhisinde oldukça yararlıdır. Production'da ek log hacmi ve hassas stack bilgisi göz önünde bulundurulmalıdır. Warning stack'i root cause'u gösterse bile cleanup branch'leri ayrıca incelenmelidir.
Event Listener Cleanup Pattern'leri
Listener cleanup için en güvenli yaklaşım registration ile removal davranışını aynı lifecycle contract içinde düşünmektir. Event yalnız bir kez bekleniyorsa `once()` otomatik removal sağlar. Uzun subscription gerekiyorsa `off()` veya `removeListener()` belirli kapanış noktasında çağrılmalıdır. Request, socket veya AbortSignal gibi lifecycle event'leri cleanup trigger olarak kullanılabilir. Cleanup function'ın idempotent olması birden fazla kapanış yolunda double cleanup hatalarını azaltır.
once()
`once()` listener'ın ilk event sonrasında otomatik kaldırılmasını sağlar. Tek response veya tek initialization event'i bekleyen flow'larda manual cleanup ihtiyacını azaltır. Event hiç gerçekleşmezse listener yine emitter üzerinde kalabilir. Bu nedenle timeout veya abort ihtiyacı varsa ayrıca cleanup düşünülmelidir. “Bir kez çalışacak” assumption'ının gerçekten business flow ile uyumlu olması gerekir.
off()
`off()` daha önce eklenen listener'ı kaldırmak için modern ve okunabilir API sunar. Removal için aynı function reference gerektiğinden inline anonymous callback kullanımı cleanup'ı zorlaştırabilir. Listener reference ayrı değişkende tutulmalıdır. Cleanup branch success, error ve cancellation yollarında çalışmalıdır. Test sonunda listener count kontrolü bu davranışı güvence altına alır.
removeListener()
`removeListener()` EventEmitter'ın uzun süredir mevcut listener kaldırma yöntemidir. `off()` birçok durumda bunun alias'ı gibi kullanılabilir. Legacy codebase'lerde yaygın olduğu için memory review sırasında özellikle aranmalıdır. Removal function reference eşleşmesi yine önemlidir. API seçimi değil cleanup'ın gerçekten her lifecycle sonunda çalışması asıl konudur.
Request Close Event
HTTP request client bağlantısı erken kapandığında associated listener ve asynchronous operation'ların devam etmesi gereksiz olabilir. Close veya abort sinyali cleanup için kullanılabilir. Pending database veya downstream request cancellation destekliyorsa aynı lifecycle'a bağlanabilir. Böylece disconnected client için memory ve CPU tüketimi azaltılır. Adapter ve framework davranışı integration test ile doğrulanmalıdır.
Socket Close Event
WebSocket veya TCP socket kapandığında room membership, timer ve listener'lar temizlenmelidir. Yalnız normal disconnect değil error ve timeout path'leri de cleanup çalıştırmalıdır. Bir socket object'i global collection'da kalırsa bağlantı fiziksel olarak kapanmış olsa bile memory leak oluşabilir. Active socket count ile collection size metrikleri karşılaştırılabilir. Cleanup sonrası stale connection bulunmadığı soak testte doğrulanmalıdır.
Cleanup Function
Bir resource oluşturulduğunda ona karşılık gelen cleanup function aynı module içinde tanımlanmalıdır. Function listener, timer ve pending queue entry'lerini birlikte kapatabilir. Idempotent davranış sayesinde error ve finally bloklarından güvenle çağrılabilir. Resource owner net olduğunda başka component'lerin cleanup sorumluluğu taşıması gerekmez. Bu pattern test edilebilir resource lifecycle oluşturur.
AbortSignal ile Cleanup
AbortSignal cancellation'ı birden fazla async operation arasında yaymak için kullanılabilir. Güncel Node.js Events API'sinde AbortSignal ile listener cleanup'ını kolaylaştıran yardımcı API'ler de bulunur. Request timeout veya client disconnect tek signal üzerinden downstream operation'ları iptal edebilir. Signal üzerinde sınırsız listener birikmesini yine takip etmek gerekir. Cancellation design yalnız memory değil gereksiz I/O kullanımını da azaltır.
setInterval ve Timer Memory Leak'leri
Timer'lar callback function'a referans tuttuğu için callback'in closure state'i timer yaşamı boyunca bellekte kalabilir. `setInterval` özellikle temizlenmediğinde process kapanana kadar tekrar çalışmaya devam eder. Per request interval oluşturmak çoğu API için ciddi memory ve CPU riskidir. Timer owner hangi event'te kapatacağını açıkça belirlemelidir. Graceful shutdown sırasında uzun ömürlü application timer'larının da temizlenmesi gerekir.
Timer Callback Referansı
Timer runtime callback function'ı sonraki execution için saklar. Callback closure içinde object kullanıyorsa bu object reachable kalabilir. Interval çok seyrek çalışsa bile referans yaşamaya devam eder. Heap snapshot'ta timer veya closure retaining path'i görülebilir. Callback yalnız gerekli küçük state'i capture edecek şekilde tasarlanmalıdır.
Closure İçindeki Büyük Objeler
Timer callback bir config subset yerine dev bir object graph capture ederse retained size beklenenden yüksek olabilir. Özellikle request body veya büyük query result timer closure içinde tutulmamalıdır. Gerekli primitive alanlar ayrı değişkene çıkarılabilir. Timer scope daraltıldığında GC'nin geri kazanabileceği object miktarı artar. Allocation snapshot bu değişikliğin etkisini doğrulayabilir.
Per-Request Interval Riski
Her request için interval oluşturmak request completion sonrasında binlerce aktif timer bırakabilir. Bu yalnız memory değil event loop üzerindeki timer callback yükünü de artırır. Request bazlı timeout gerekiyorsa tek `setTimeout` ve explicit cleanup daha uygun olabilir. Shared scheduler gerekiyorsa merkezi ve bounded job registry tasarlanmalıdır. Active timer sayısı debug metriklerinde izlenebilir.
clearInterval
`clearInterval` interval'in tekrar schedule edilmesini durdurur ve runtime reference'larının bırakılmasına yardımcı olur. Cleanup success ve error path'lerinde çağrılmalıdır. Interval handle class state içinde tutuluyorsa `close()` method'u üzerinden temizlenebilir. Double clear çoğu durumda sorun oluşturmasa da idempotent contract daha açık tasarım sağlar. Unit test fake timer kullanarak cleanup'ı doğrulayabilir.
clearTimeout
Timeout tetiklenmeden operation tamamlanırsa timer gereksiz yere yaşamaya devam edebilir. `clearTimeout` completion sonrası bu handle'ı kapatır. Timeout callback büyük state capture ediyorsa erken cleanup memory açısından daha önemlidir. Promise timeout wrapper yazarken timer'ın resolve ve reject yollarında temizlendiğinden emin olunmalıdır. `finally` bu amaç için okunabilir bir yapı sağlayabilir.
Timer Lifecycle
Her timer için oluşturma, aktif kullanım ve cleanup noktası tanımlanmalıdır. Application-level cron benzeri timer process lifetime'a bağlı olabilir. Request-level timer ise request veya operation lifetime ile sınırlı olmalıdır. Shutdown sırasında yeni timer üretimi durdurulmalı ve mevcut timer'lar kapatılmalıdır. Lifecycle dokümantasyonu timer kaynaklı leak'lerin code review sırasında görülmesini kolaylaştırır.
Promise Kaynaklı Memory Problemleri
Promise tek başına leak oluşturmaz ancak uzun süre tamamlanmayan operasyonlar closure state ve callback chain'lerini bellekte tutabilir. Sınırsız sayıda pending Promise özellikle dependency outage sırasında memory büyümesine neden olabilir. Timeout, cancellation ve concurrency limit bu riskin temel kontrolleridir. Pending request count ve queue depth monitoring'e eklenmelidir. `Promise.all()` gibi toplu yapılar büyük result set'leri aynı anda bellekte tutabileceği için workload boyutu sınırlandırılmalıdır.
Uzun Süre Bekleyen Promise
Remote API veya database response'u çok gecikirse Promise state ve bağlı callback'ler request tamamlanana kadar tutulur. Az sayıda operation için bu normaldir. Ancak binlerce concurrent request aynı dependency üzerinde bekliyorsa memory footprint hızlı büyüyebilir. Client timeout kadar server-side dependency timeout da uygulanmalıdır. Pending operation metriği latency alert'inden önce kapasite problemine işaret edebilir.
Asla Resolve Olmayan Promise
Bug nedeniyle resolve veya reject edilmeyen Promise özellikle onu tutan collection varsa kalıcı retention oluşturabilir. Event callback'i hiç gelmiyorsa promise wrapper açık kalabilir. Timeout branch bu tür failure mode'ları sınırlamaya yardımcı olur. Heap snapshot pending Promise ve bağlı closure'ları gösterebilir. Promise oluşturulan her integration'da completion ve cancellation sözleşmesi tanımlanmalıdır.
Closure Retention
Promise callback'leri lexical scope'taki büyük object'leri capture edebilir. Operation tamamlanana kadar bu object'lerin GC olması mümkün olmayabilir. Büyük request body yerine yalnız identifier veya gerekli primitive alan callback'e taşınmalıdır. Long polling veya retry flow'larında bu fark oldukça büyüyebilir. Retained size analizi küçük Promise callback'inin arkasındaki büyük graph'ı gösterebilir.
Timeout
Timeout bir operation'ın ne kadar süre resource tutabileceğine üst sınır getirir. HTTP, database ve queue operation'larında ayrı timeout budget'lar tanımlanmalıdır. Timeout yalnız Promise'i reject edip underlying I/O'yu iptal etmiyorsa resource tüketimi devam edebilir. Bu nedenle mümkün olduğunda cancellation destekleyen API kullanılmalıdır. Timeout değerleri rastgele değil P99 dependency latency ve overall request deadline üzerinden belirlenmelidir.
Cancellation
Cancellation artık sonucu kullanılmayacak operation'ın erken sonlandırılmasını sağlar. Client disconnect veya request deadline bu kararı tetikleyebilir. Database driver veya HTTP client cancellation destekliyorsa AbortSignal ile propagation kurulabilir. Cancellation sonrası listener ve timer cleanup da yapılmalıdır. Operation cancellation metriği dependency sağlığı hakkında ek sinyal sağlayabilir.
AbortController
`AbortController` cancellation signal üretmek için standart bir API sunar. Aynı signal HTTP request, stream veya başka desteklenen operation'lara geçirilebilir. Parent request iptal edildiğinde child operations birlikte durdurulabilir. Controller lifecycle request tamamlandığında bırakılmalıdır. Signal listener cleanup'ı kullanılan API tarafından yapılmıyorsa manual cleanup contract da kontrol edilmelidir.
Closure Memory Leak Nasıl Oluşur?
Closure bir function'ın tanımlandığı lexical scope'taki değişkenlere sonradan erişebilmesini sağlar. Bu özellik JavaScript için temel ve yararlıdır fakat scope'taki büyük object'lerin beklenenden uzun süre tutulmasına da yol açabilir. Listener, timer veya pending Promise closure'ları tipik risk alanlarıdır. Leak teşhisinde function'ın kendisi küçük görünürken retained size çok büyük olabilir. Çözüm scope'u daraltmak ve yalnız gerçekten gerekli değerleri capture etmektir.
Closure Scope
Bir callback outer scope'taki değişkenleri kullandığında V8 gerekli context'i yaşamaya devam ettirebilir. Kullanılmayan bütün outer variable'ların her zaman tutulduğu gibi basit bir varsayım yapmak doğru değildir, runtime optimizasyonları değişebilir. Yine de kod tasarımında büyük object graph'ı uzun callback lifetime'ına bağlamamak güvenli yaklaşımdır. Heap snapshot gerçek retaining path'i göstereceği için varsayımdan daha güçlü kanıt sağlar. Closure review özellikle event-driven code'da yapılmalıdır.
Büyük Request Body'yi Tutmak
Request body birkaç megabyte büyüklüğünde olabilir. Asynchronous callback yalnız user ID'ye ihtiyaç duyarken bütün body'yi closure içinde referans ediyorsa memory gereksiz yere tutulur. Gerekli identifier önce primitive değişkene alınabilir. Callback tamamlanana kadar büyük payload artık retained kalmaz. Upload veya bulk API'lerde bu pattern concurrency ile çarpıldığı için ciddi fark oluşturabilir.
Büyük Configuration Objelerini Tutmak
Global configuration zaten process boyunca yaşayacaksa closure capture ek risk yaratmayabilir. Ancak per tenant veya per request üretilen büyük configuration object farklıdır. Background callback yalnız birkaç field'a ihtiyaç duyuyorsa subset çıkarılmalıdır. Bu yaklaşım retaining graph'ı küçültür. Per tenant cache ile closure birlikte kullanılıyorsa memory quota ayrıca düşünülmelidir.
Scope'u Daraltmak
Variable yalnız kullanıldığı block içinde oluşturulduğunda ownership daha görünür olur. Büyük intermediate object function dışına taşınmamalıdır. Async callback'in ihtiyaç duyduğu minimal state explicit parametre ile aktarılabilir. Bu kod okunabilirliğini de artırır çünkü dependency listesi görünür hâle gelir. Heap profile optimizasyon öncesi ve sonrası farkı ölçmek için kullanılabilir.
Yalnızca Gerekli Primitive Değerleri Capture Etmek
Callback bütün user object yerine yalnız `userId` veya status code kullanıyorsa primitive değerleri ayrı capture etmek daha hafiftir. Büyük nested graph'a referans kalmadığında GC diğer owner'lar da bırakmışsa bu veriyi temizleyebilir. Bu yaklaşım özellikle timer, retry ve queue callback'lerinde yararlıdır. Ancak object daha sonra yeniden ihtiyaç duyulacaksa sırf memory için tekrar database query yapmak latency maliyeti getirebilir. Karar data boyutu ve operation lifetime üzerinden verilmelidir.
Global ve Module-Level State Riskleri
Node.js module'leri process içinde cache'lendiği için module-level variable'lar çoğu zaman process lifetime boyunca yaşar. Bu durum configuration veya singleton service için yararlı olabilir. Request verisini module-level collection'a eklemek ise kalıcı reference riskini yükseltir. Global state büyüklüğü ve ownership'i code review'da açıkça görülmelidir. Stateless API hedefi request'e ait state'in process genelinde birikmesini engelleyen güçlü bir varsayımdır.
Global Object
`globalThis` üzerine yazılan değerler process boyunca erişilebilir kalabilir. Application module'leri arasında kolay paylaşım sağlasa da dependency ownership'i gizler. Request cache veya user state'i global object üzerinde tutulmamalıdır. Configuration için bile typed dependency injection veya explicit module daha okunabilir olabilir. Heap snapshot global root üzerinden retained graph'ı gösterebilir.
Module Cache
Node.js yüklenen module'leri tekrar kullanmak için cache mekanizmasına sahiptir. Module-level singleton ve collection'lar bu nedenle function return ettikten sonra da yaşamaya devam edebilir. Bu davranış normaldir ancak state'in sınırsız büyümemesi gerekir. Hot reload veya test environment module cache davranışı production ile farklı olabilir. Memory test gerçek process lifecycle'a yakın çalıştırılmalıdır.
Singleton
Singleton service process yaşamı boyunca bir instance taşır. Logger, config veya shared client için bu uygundur. Ancak singleton içindeki Map request verisi saklamaya başlarsa doğal olarak uzun ömürlü cache oluşur. Her singleton collection için size ve cleanup policy sorgulanmalıdır. Dependency injection scope memory ownership'i otomatik çözmez.
Module-Level Array
Module-level array'a her request'te event eklemek en basit leak örneklerinden biridir. Array process restart olana kadar büyümeye devam eder. Debug history amacıyla kullanılıyorsa ring buffer gibi bounded yapı tercih edilmelidir. Array length metric hızlı alarm sağlayabilir. Persistent audit log için database veya event system kullanılmalıdır.
Module-Level Map
Module-level Map cache için sık kullanılır. TTL ve maximum size yoksa process uptime ile birlikte büyüyebilir. Multi tenant servislerde tenant başına benzersiz key sayısı çok yüksek olabilir. LRU veya bounded cache abstraction kullanılmalıdır. Map size ve estimated bytes production dashboard'a eklenmelidir.
Request Verisini Global State'e Yazmamak
Request body, user object veya response verisi global state içinde tutulmamalıdır. Debug amaçlı son request kaydı bile sensitive data ve memory riski taşır. Correlation için yalnız küçük identifier structured log veya AsyncLocalStorage context'te kullanılabilir. Request state request tamamlandığında doğal olarak reachable olmaktan çıkmalıdır. Bu principle stateless horizontal scaling davranışını da kolaylaştırır.
AsyncLocalStorage Bellek Yönetimi
AsyncLocalStorage request boyunca correlation ID veya tenant context gibi bilgileri parametre taşımadan erişilebilir hâle getirir. Node.js bu API'yi asynchronous context propagation için optimize edilmiş bir çözüm olarak sunar. Buna rağmen store içine büyük request body veya entity graph koymak context lifetime boyunca bu veriyi retained tutabilir. Uzun ömürlü async resource'lar request context'in beklenenden uzun yaşamasına neden olabilir. Store küçük tutulmalı ve AsyncLocalStorage instance lifecycle'ı uygulama tasarımına uygun yönetilmelidir.
AsyncLocalStorage Nedir?
AsyncLocalStorage asynchronous callback ve Promise zincirleri boyunca aynı store'a erişim sağlar. Request ID, trace context veya küçük tenant metadata bu yapı için iyi örneklerdir. Manuel olarak `async_hooks` üzerinde benzer sistem kurmak yerine Node.js'in optimize edilmiş AsyncLocalStorage API'si tercih edilmelidir. Store business state deposu değildir. Context yalnız cross-cutting request bilgilerini taşımalıdır.
Request Context
HTTP middleware request başında `run()` ile yeni context oluşturabilir. Request boyunca logger ve service aynı store'dan correlation bilgisi okuyabilir. Context içine request object'in tamamını koymak gereksiz reference chain oluşturabilir. Minimal field set memory kullanımını ve coupling'i azaltır. Request tamamlandığında ilgili async resource'lar bittiği sürece store da GC için uygun hâle gelir.
Correlation ID
Correlation ID küçük string value olduğu için AsyncLocalStorage kullanımına uygundur. Logger her event'te bu değeri store'dan okuyabilir. Developer'ın her service method'una request ID parametresi taşımasına gerek kalmaz. Correlation ID metric label yapılmamalıdır çünkü cardinality çok yüksektir. Log ve trace correlation için ise oldukça değerlidir.
Store İçine Büyük Objeler Koymanın Riski
Store'a request body veya büyük user entity koymak bütün async chain boyunca reference tutabilir. Operation beklenenden uzun sürerse bu memory daha uzun süre serbest bırakılamaz. Sadece user ID veya tenant ID gibi küçük değerler taşımak daha güvenlidir. İhtiyaç duyulan business object service layer'da explicit olarak yönetilebilir. Heap snapshot AsyncLocalStorage context üzerinden retaining path gösterebilir.
Uzun Ömürlü Async Resources
Request içinde başlatılan timer, socket veya hiç tamamlanmayan Promise async context'i uzatabilir. Böylece request response dönmüş olsa bile context store yaşamaya devam edebilir. Pending async resource sayısı leak investigation sırasında incelenmelidir. Cancellation ve cleanup mekanizmaları bu lifetime'ı sınırlar. Per request background task gerekiyorsa request context'ten ayrılmış explicit job context daha doğru olabilir.
Async Context Lifecycle
Async context request veya operation lifetime ile uyumlu olmalıdır. Request sona erdiğinde yeni background operation'ların yanlışlıkla aynı context'i miras alması engellenmelidir. Detached task gerekiyorsa yeni context başlatılabilir. Logger store bulunmadığında güvenli fallback davranışı göstermelidir. Context propagation integration test ile async boundary'lerde doğrulanmalıdır.
disable() ve Instance Lifecycle
Node.js belgelerine göre kullanılmayan AsyncLocalStorage instance'ının kendisinin garbage collect edilebilmesi için `disable()` çağrısı gerekir. Bu durum store object'leriyle aynı şey değildir çünkü store'lar bağlı async resource'larla birlikte collection'a uygun hâle gelir. Application boyunca tek singleton AsyncLocalStorage kullanılıyorsa sürekli disable etmek gerekmez. Dynamic olarak instance oluşturulan library tasarımlarında lifecycle daha dikkatli yönetilmelidir. `disable()` sonrası context davranışı test edilerek beklenmeyen state kaybı önlenmelidir.
Database Connection Pool Kaynaklı Memory Problemleri
Database pool problemi yalnız connection sayısı ile sınırlı değildir, bekleyen query queue'su ve büyük result set'ler de memory footprint'i yükseltebilir. Connection release edilmediğinde pool kapasitesi azalır ve yeni request'ler sırada birikmeye başlar. Pending request state'i arttıkça heap büyüyebilir. Query timeout, pool size ve queue limit birlikte tasarlanmalıdır. Database pool metrikleri memory dashboard'a eklenerek connection pressure ile heap büyümesi arasındaki ilişki görülebilir.
Connection Leak
Connection pool'dan alınan client geri verilmezse zamanla kullanılabilir connection sayısı düşer. Her leaked client açık socket ve driver state'i taşıyabilir. Pool exhaustion yeni query'lerin beklemesine neden olur. Leak genellikle error veya early return path'inde ortaya çıkar. Acquire ve release sayıları metric olarak izlenirse imbalance erken fark edilebilir.
Client Release Etmemek
Manual connection acquisition kullanan kodda release çağrısı zorunludur. Success path'te release bulunup error path'te unutulması sık görülen hatadır. `finally` bloğu bu sorumluluğu tek yerde toplar. Transaction API kendi callback lifecycle'ını yönetiyorsa library contract doğru anlaşılmalıdır. Connection object global collection'da saklanmamalıdır.
Error Path'te Connection Kaybetmek
Query exception fırlattığında sonraki satırdaki release çağrısına ulaşılmayabilir. Bu nedenle cleanup normal execution sırasına bırakılmamalıdır. `try` ve `finally` pattern'i resource management için güvenilir bir yapı sağlar. Error sırasında transaction rollback de aynı lifecycle içinde ele alınmalıdır. Fault injection test connection leak'ini yakalamak için faydalıdır.
finally
`finally` success veya exception fark etmeksizin cleanup çalıştırır. Database client release, timer cancel veya temporary file cleanup için kullanılabilir. Cleanup'ın kendisi exception üretirse original error'ı gizlememelidir. Resource release idempotent tasarlanmalıdır. Unit test hem başarılı hem başarısız query senaryosunda release çağrısını doğrulamalıdır.
Pool Size
Pool size yalnız CPU core sayısına göre seçilmemelidir. Database server connection kapasitesi, pod replica sayısı ve query concurrency birlikte düşünülmelidir. Her pod 50 connection açıp 100 replica çalıştırırsa database üzerinde beş bin connection oluşabilir. Büyük pool memory ve socket footprint'ini de artırır. Gerçek workload benchmark ve database utilization değerleri üzerinden boyutlandırma yapılmalıdır.
Connection Queue
Pool dolduğunda yeni acquisition request'leri queue'ya alınabilir. Sınırsız queue dependency outage sırasında binlerce pending Promise ve request state'i biriktirebilir. Acquisition timeout ve queue limit bu riski azaltır. Kapasite dolduğunda hızlı failure veya load shedding daha sağlıklı olabilir. Queue depth production alarmı olarak izlenmelidir.
Query Result Memory
Connection sağlıklı olsa bile query milyonlarca row döndürüyorsa application heap ciddi şekilde büyüyebilir. ORM entity hydration plain row'dan daha fazla object allocation oluşturabilir. Pagination, cursor ve stream query büyük sonuçlarda daha güvenlidir. Yalnız gerekli column'ları select etmek memory ve network kullanımını azaltır. Query result size load testte gerçek production dağılımıyla ölçülmelidir.
ORM Kullanımında Bellek Yönetimi
ORM geliştirme hızını artırırken result set'in object graph'a dönüştürülmesi memory maliyetini yükseltebilir. Eager loading büyük relation graph'larını tek request için belleğe alabilir. Identity map veya entity tracking kullanan ORM'lerde context lifetime uzadıkça tutulan entity sayısı da artabilir. Pagination ve projection bu maliyeti sınırlar. ORM query'leri SQL performansı kadar application heap etkisi açısından da review edilmelidir.
Büyük Result Set
Binlerce database row JavaScript object'e dönüştürüldüğünde raw payload'dan daha fazla heap kullanabilir. Her field, relation ve ORM metadata ek allocation oluşturur. Export veya batch job'larında bütün sonucu tek seferde almak peak memory'yi artırır. Cursor veya stream processing daha sabit footprint sağlayabilir. Result count için hard veya operational limit tanımlanmalıdır.
Eager Loading
Eager loading gerekli relation'ları kolayca getirir ancak nested relation sayısı büyüdükçe object graph hızla genişleyebilir. Endpoint yalnız birkaç field kullanıyorsa bütün graph'ı hydrate etmek gereksizdir. Explicit projection daha hafif response üretir. Query plan ve heap allocation birlikte benchmark edilmelidir. Eager loading policy endpoint ihtiyacına göre seçilmelidir.
N+1 Problemi ile Memory Arasındaki İlişki
N+1 çoğu zaman database latency problemi olarak ele alınır fakat memory üzerinde de etkisi olabilir. Çok sayıda query Promise'i ve result object'i aynı request boyunca birikebilir. Concurrency kontrolsüzse connection queue ve heap birlikte büyür. Batch query veya DataLoader benzeri yaklaşım query count'u azaltabilir. Yine de batch result boyutu da sınırlandırılmalıdır.
Identity Map / Entity Tracking
Bazı ORM'ler aynı transaction veya context boyunca entity instance'larını takip eder. Uzun ömürlü context binlerce entity'yi memory'de tutabilir. Request-scoped kısa context bu riski azaltır. Background job büyük dataset işliyorsa context belirli batch'lerde reset edilebilir. ORM dokümantasyonundaki tracking lifecycle uygulama architecture'ına göre incelenmelidir.
Pagination
Pagination tek request'te işlenen row sayısına üst sınır getirir. Offset pagination basit olsa da çok büyük offset database maliyeti oluşturabilir. Memory açısından page size bounded olduğu sürece avantaj sağlar. Client'ın `limit=1000000` göndermesine izin verilmemelidir. Server-side maximum page size zorunlu olmalıdır.
Cursor
Cursor tabanlı pagination büyük dataset'lerde stabil page geçişi sağlayabilir. Query yalnız sonraki belirli sayıda row getirir. Application bütün dataset'i memory'de tutmak zorunda kalmaz. Cursor opaque ve doğrulanmış biçimde kullanılmalıdır. Export gibi long-running flow'larda cursor ile batch processing iyi bir memory control sağlar.
Stream Query
Driver veya ORM row streaming destekliyorsa result'lar chunk halinde işlenebilir. Bu model bütün row'ları array içine toplamaktan daha düşük peak memory sağlayabilir. Consumer yavaşsa backpressure davranışı önemlidir. Transaction ve connection stream bitene kadar açık kalacağı için timeout ve cleanup gerekir. Stream error path'inde connection release test edilmelidir.
Büyük SQL Sonuçları Nasıl İşlenmeli?
Büyük SQL sonuçları Node.js heap'ine tek seferde yüklenmemelidir. Projection ile yalnız gerekli field'lar alınmalı, data page veya cursor üzerinden küçük parçalar hâlinde işlenmelidir. Export gibi use case'lerde row stream doğrudan output stream'e bağlanabilir. Batch size hem database throughput hem process memory üzerinden benchmark edilmelidir. Bu yaklaşım büyük result set nedeniyle oluşan transient OOM riskini önemli ölçüde azaltır.
SELECT * Problemi
`SELECT *` endpoint'in kullanmadığı column'ları da network ve application memory'ye taşır. Büyük text veya JSON column'ları memory footprint'i ciddi biçimde artırabilir. Explicit projection schema değişikliklerinin response'a istemeden yansımasını da engeller. ORM query builder'da yalnız gerekli alanlar seçilmelidir. Query payload byte metriği optimizasyon etkisini gösterebilir.
Pagination
Server belirli maksimum row sayısını page başına zorunlu kılmalıdır. Client tarafından gelen limit doğrudan güvenilmemelidir. Pagination memory kullanımını request başına bounded hâle getirir. Ancak yüksek concurrent page request toplam process footprint'i yine artırabilir. Concurrency ve page size birlikte capacity test edilmelidir.
Cursor-Based Processing
Cursor büyük dataset üzerinde sırayla ilerlemeyi sağlar. Her batch işlendiğinde önceki veriler referanslardan çıkarılarak GC'ye bırakılabilir. Cursor state küçük tutulmalıdır. Error durumunda kaldığı yerden devam strategy business requirement'a göre tasarlanabilir. Cursor lifetime database connection ve transaction limitleriyle uyumlu olmalıdır.
Row Streaming
Row streaming database'den gelen kayıtları tek tek veya küçük chunk'lar hâlinde işler. Application büyük array oluşturmaz. Output consumer yavaşsa stream pause veya backpressure mekanizması kullanılmalıdır. Error geldiğinde pipeline bütün kaynakları kapatmalıdır. Streaming library'nin cleanup behavior'ı integration test ile doğrulanmalıdır.
Batch Processing
Batch processing örneğin her seferinde 500 veya 1000 row işleyebilir. Batch size büyüdükçe throughput artabilir fakat peak memory de yükselir. Çok küçük batch database round trip sayısını artırır. Doğru değer gerçek workload benchmark ile bulunmalıdır. Her batch sonunda büyük temporary collection referansları bırakılmalıdır.
Projection
Projection yalnız ihtiyaç duyulan column ve computed value'ların alınmasıdır. Daha küçük row hem network transferini hem JavaScript allocation'ını azaltır. API response DTO ile database projection mümkün olduğunca uyumlu tutulabilir. Domain logic tüm entity'ye ihtiyaç duyuyorsa aşırı projection code complexity oluşturabilir. Hot query'lerde ölçüm üzerinden karar verilmelidir.
Node.js Buffer Belleği Nasıl Çalışır?
Buffer Node.js'in binary veri işlemesinde merkezî bir role sahiptir. Dosya, TCP, TLS ve birçok protocol API'si Buffer nesneleriyle çalışır. Buffer tarafından kullanılan memory V8 heap'in dışında bulunabildiği için heapUsed metriği tek başına gerçek footprint'i göstermez. `external` ve `arrayBuffers` alanları bu nedenle önemlidir. Büyük binary workload'larda Buffer lifetime ve stream backpressure memory güvenliğinin temel parçalarıdır.
Buffer Nedir?
Buffer byte dizilerini işlemek için Node.js tarafından sağlanan yapıdır. Text encoding, network packet ve file chunk gibi veriler bu yapı üzerinden işlenebilir. Buffer normal JavaScript object wrapper'a sahip olsa da underlying memory davranışı klasik object'ten farklıdır. Büyük Buffer array'lerini collection içinde tutmak process RSS'ini hızla büyütebilir. Buffer referansı bırakıldığında ve başka owner kalmadığında memory zamanla geri kazanılabilir.
Buffer'ın V8 Heap Dışındaki Belleği
Buffer data'nın önemli kısmı V8 managed heap dışında tutulabilir. Bu nedenle 500 MB Buffer kullanan process'te heapUsed aynı miktarda artmayabilir. JavaScript tarafındaki Buffer wrapper yine object graph içinde reference taşır. Wrapper retained kaldıkça underlying data da serbest bırakılamaz. Buffer leak teşhisinde external ve RSS trendleri heap snapshot bilgisiyle birlikte okunmalıdır.
external
`external` Buffer ve başka externalized allocation'lar hakkında genel sinyal sağlar. Değer trafik artışıyla yükselip sonra düşüyorsa workload kaynaklı geçici kullanım olabilir. Sürekli baseline artışı reference retention veya native library problemi düşündürür. External alarmı heapUsed alarmından ayrı eşikle tasarlanabilir. Container limit headroom hesabında external memory mutlaka yer almalıdır.
arrayBuffers
`arrayBuffers` daha spesifik olarak ArrayBuffer, SharedArrayBuffer ve Node Buffer kullanımını izlemeye yardımcı olur. Değer external'ın subset'i olduğu için toplam hesapta iki kez sayılmamalıdır. Binary processing servisinde arrayBuffers grafiği request rate ile birlikte değerlendirilebilir. Upload tamamlandığında değerin baseline'a dönmemesi retained Buffer ihtimalini güçlendirir. Per request buffer byte metriği debugging için eklenebilir.
Büyük Buffer Allocation
Tek seferde yüzlerce megabyte Buffer ayırmak container memory limitini hızla zorlayabilir. Concurrent request sayısı ile bu miktar çarpılır. `Buffer.concat` gibi işlemler yeni büyük allocation oluşturabilir ve kısa süre iki kopya birden memory'de bulunabilir. Büyük payload mümkünse chunk halinde işlenmelidir. Payload size limit ve concurrency limit birlikte uygulanmalıdır.
Buffer Pool
Node.js küçük Buffer allocation'larında internal pool gibi optimizasyonlar kullanabilir. Bu nedenle allocated memory ile aktif business payload miktarı birebir aynı görünmeyebilir. Application kendi sınırsız Buffer pool'unu oluşturmak yerine runtime davranışını ve gerçek ihtiyacını ölçmelidir. Custom pool memory'nin işletim sistemine geri dönmesini geciktirebilir. Pool kullanımı benchmark ile doğrulanmadan production optimization olarak eklenmemelidir.
Buffer Leak ile Heap Leak Arasındaki Fark
Heap leak ve Buffer leak aynı process RSS artışını üretse de farklı metriklerde görünür. JavaScript object leak genellikle heapUsed baseline'ını yükseltir. Buffer ağırlıklı retention'da external ve arrayBuffers daha belirgin artabilir. Heap snapshot JavaScript wrapper veya retaining path'i gösterebilir fakat native byte miktarı konusunda eksik kalabilir. Bu ayrım production Node.js uygulamalarında heap snapshot memory profiling ve monitoring yöntemleri kullanılırken teşhis aracının doğru seçilmesini sağlar.
Heap Used Sabit
RSS artarken heapUsed stabilse klasik JavaScript heap leak hipotezi zayıflar. Bu durum Buffer, native addon veya allocator fragmentation ihtimalini artırır. Yine de düşük miktarda JavaScript reference büyük external allocation'ı tutabileceği için heap tamamen göz ardı edilmemelidir. Snapshot retainers Buffer wrapper owner'ını gösterebilir. External memory metriği bir sonraki kritik kontroldür.
External Memory Büyüyor
External memory'nin sürekli yükselmesi heap dışı tracked allocation'ların arttığını gösterir. Buffer veya ArrayBuffer workload ilk aday olabilir. Request completion sonrasında external baseline düşmüyorsa retained reference araştırılmalıdır. Package-level native allocation da aynı metriğe katkıda bulunabilir. Minimal reproduction ile ilgili feature kapatılıp açılarak fark ölçülebilir.
RSS Büyüyor
RSS process'in toplam resident memory footprint'ini yansıtır. Heap ve external artışı RSS'e katkıda bulunur fakat native fragmentation gibi başka nedenler de vardır. Container OOM açısından en kritik sonuç genellikle RSS veya cgroup memory kullanımında görülür. RSS artış hızı leak rate metric olarak takip edilebilir. Root cause sınıflandırması diğer memory alanlarıyla yapılmalıdır.
Heap Snapshot'ta Problemi Görememek
Heap snapshot V8 object graph'ına odaklandığı için native memory'nin tamamını temsil etmez. Bu nedenle snapshot comparison temiz görünürken RSS büyümeye devam edebilir. Buffer wrapper sayısı az fakat her wrapper büyük external block tutuyor olabilir. Native addon leak'i hiç görünmeyebilir. Böyle durumda snapshot'a tekrar tekrar bakmak yerine diagnostic report ve native profiler aşamasına geçilmelidir.
Native Memory Profiling Gereksinimi
HeapUsed ve external açıklama getirmiyorsa operating system ve native allocation araçları gerekebilir. Linux üzerinde allocator profiling veya native stack sampling kullanılabilir. Native dependency'ler tek tek devre dışı bırakılarak binary search yapılabilir. Reproduction staging ortamına taşınarak production riskinden kaçınılır. Root cause bulunduğunda dependency upgrade, patch veya architecture değişikliği aynı workload ile tekrar benchmark edilmelidir.
Büyük Dosyalar Node.js'te Nasıl İşlenmeli?
Büyük dosyanın tamamını RAM'e almak basit kod üretir fakat concurrency arttığında process memory hızla büyür. Node.js stream API'si dosyayı chunk'lar hâlinde işlemek için daha uygun model sunar. `pipeline()` error propagation ve cleanup açısından manual pipe zincirlerinden daha güvenli olabilir. Upload ve download endpoint'lerinde backpressure korunmalıdır. Dosya boyutu, concurrency ve highWaterMark değerleri gerçek production benzeri workload ile test edilmelidir.
readFile() ile Tüm Dosyayı Belleğe Alma
`readFile()` bütün file content'i memory'ye yükler. 500 MB dosya tek request için mümkün görünse bile on concurrent request birkaç gigabyte allocation oluşturabilir. File ayrıca parse veya transform edilirken ikinci kopyalar oluşabilir. Küçük config file için `readFile()` gayet uygundur, sorun dosya boyutu ve concurrency sınırı bilinmediğinde başlar. Büyük payload için stream tercih edilmelidir.
ReadStream
ReadStream file content'i küçük chunk'lar hâlinde üretir. Consumer hızına göre flow kontrol edildiğinde memory footprint daha sabit kalır. Stream error ve close event'leri cleanup contract'a dahil edilmelidir. Dosya handle'ı pipeline tamamlandığında kapanmalıdır. Chunk başına ağır async işlem varsa concurrency ayrıca sınırlanmalıdır.
WriteStream
WriteStream destination'a incremental veri yazmayı sağlar. `write()` false döndürdüğünde producer daha fazla veri göndermeyi durdurmalıdır. `drain` event'i sonrasında devam etmek backpressure'ın temelidir. Bu sinyali yok saymak internal buffer'ın büyümesine yol açabilir. Disk yavaşladığında memory davranışı load testte özellikle gözlenmelidir.
pipeline()
`pipeline()` readable ve writable stream'leri tek lifecycle altında bağlar. Error oluştuğunda ilişkili stream'lerin cleanup edilmesini kolaylaştırır. Promise tabanlı pipeline API async function içinde okunabilir kullanım sunar. Backpressure zincir boyunca doğal olarak korunur. Production file processing'de manual event wiring yerine pipeline çoğu durumda daha güvenilir bir temel sağlar.
Chunk-Based Processing
Chunk bazlı processing bütün payload yerine küçük bölümleri sırayla işler. Compression, hashing veya transform gibi işler bu modelle yapılabilir. Chunk size büyüdükçe function call overhead azalabilir fakat memory artar. Çok küçük chunk ise throughput'u düşürebilir. Benchmark doğru dengeyi belirlemelidir.
Upload Streaming
Upload file'ı önce tamamen Buffer'a almak yerine object storage veya disk target'a stream etmek peak memory'yi azaltır. Multipart parser'ın kendi buffer limitleri de ayarlanmalıdır. Client çok yavaş gönderiyorsa connection timeout ve rate limit gerekir. Upload boyutu business policy ile sınırlandırılmalıdır. Failed upload temporary resource cleanup kesin olarak yapılmalıdır.
Download Streaming
Büyük download response'u memory'de tek Buffer olarak oluşturmak gereksiz footprint yaratabilir. Source stream doğrudan HTTP response pipeline'a bağlanabilir. Client yavaşsa backpressure source reading hızını sınırlar. Range request veya resume requirement varsa stream strategy buna göre planlanır. Disconnect durumunda source stream kapatılmalıdır.
Stream Backpressure Nedir?
Backpressure producer'ın consumer'dan daha hızlı veri üretmesi durumunda memory'nin sınırsız büyümesini engelleyen akış kontrolüdür. Node.js stream API bu davranışı internal buffer ve return value mekanizmalarıyla sağlar. Writable `write()` false döndürdüğünde producer veri göndermeye ara vermelidir. Consumer buffer'ı boşalttığında `drain` event'i devam sinyali verir. Bu kontrata uymamak yüksek RSS, daha kötü GC davranışı ve sonunda process abort riskine yol açabilir.
Producer ve Consumer Hız Farkı
Diskten hızlı okuyan producer yavaş network connection'a veri gönderiyorsa hızlar eşit değildir. Aradaki fark memory'de buffer olarak birikmeye başlar. Backpressure producer'ı consumer kapasitesine göre yavaşlatır. Bu durum throughput kaybı değil system stability için gerekli flow control'dür. Consumer sürekli yavaşsa timeout veya load shedding de gerekebilir.
Internal Buffer
Readable ve Writable stream'ler belirli miktarda data'yı internal queue içinde tutar. `highWaterMark` bu buffering davranışının eşiklerinden biridir. Bu değer strict hard memory limit değildir. Birden fazla stream ve concurrent connection toplam footprint'i büyütebilir. Capacity planning stream başına buffer ile connection sayısını birlikte hesaba katmalıdır.
write() Return Value
Writable `write()` çağrısı buffer eşik altında olduğunda true, baskı arttığında false döndürebilir. False sonucu producer'ın durması gerektiğini bildirir. Bu return value'yu görmezden gelmek yeni chunk'ların sürekli memory'de birikmesine neden olur. Manual stream producer yazarken sonuç mutlaka kontrol edilmelidir. `pipeline()` birçok yaygın durumda bu flow control'ü sizin yerinize yönetir.
'drain'
`drain` writable buffer yeterince boşaldığında yeniden yazmaya devam edilebileceğini bildirir. `write()` false sonrası producer bu event'i beklemelidir. Listener'ın tek cycle için `once('drain')` şeklinde kullanılması cleanup açısından daha güvenli olabilir. Stream destroy edilirse bekleyen continuation iptal edilmelidir. Slow destination testleri `drain` logic'ini doğrulamak için kullanılabilir.
highWaterMark
`highWaterMark` stream internal buffering eşiklerinden biridir. Güncel Node.js varsayılanları byte stream'lerde ve object mode'da farklıdır. Değer yükseltildiğinde bazı workload'larda throughput iyileşebilir ancak connection başına memory artar. Değer strict maksimum bellek limiti değildir. Her değişiklik gerçek concurrency ile benchmark edilmelidir.
Backpressure'a Uymamanın Memory Etkisi
Backpressure yok sayılırsa producer consumer'ın işleyemediği chunk'ları memory'de biriktirmeye devam eder. RSS hızla büyür ve garbage collector daha fazla object ile uğraşır. Node.js stream belgeleri bu pattern'in sonunda yüksek memory kullanımı ve process abort riskine kadar ilerleyebileceğini belirtir. Incident sırasında heap leak sanılan problem aslında queueing olabilir. Queue length ve writableLength gibi runtime sinyalleri bu ayrımı gösterebilir.
highWaterMark Nasıl Ayarlanmalıdır?
`highWaterMark` için bütün Node.js servislerine uygulanacak tek doğru sayı yoktur. Dosya, network, object mode ve transform workload'larının chunk yapıları farklıdır. Değer yükseldikçe belirli workload'larda throughput kazanılabilir fakat eş zamanlı stream sayısıyla çarpıldığında memory maliyeti büyür. Daha düşük değer memory footprint'i azaltabilir ancak daha sık flow control yaratabilir. Doğru değer latency, throughput ve RSS birlikte ölçülerek belirlenmelidir.
Byte Streams
Byte stream'lerde highWaterMark byte cinsinden buffering eşiği gibi davranır. Güncel Node.js stream varsayımları sürümlere göre değişebildiği için runtime dokümantasyonu esas alınmalıdır. File veya socket workload'unda chunk boyutu ve I/O device throughput önemlidir. Her connection için aynı buffer ayrılmasa bile concurrency toplam memory'yi etkiler. Load test gerçek connection sayısını temsil etmelidir.
Object Mode
Object mode stream'de highWaterMark byte değil object sayısı açısından ele alınır. Bir object birkaç byte veya birkaç megabyte olabilir. Bu nedenle yalnız object count memory budget için yeterli değildir. Büyük message processing'de object size ayrıca sınırlandırılmalıdır. Queue metric object count yanında estimated byte size da tutabilir.
Throughput
Daha büyük buffer producer ve consumer arasındaki kısa süreli hız farklarını absorbe ederek throughput'u iyileştirebilir. Ancak sürekli yavaş consumer varsa buffer yalnız problemi geciktirir. Throughput gain workload benchmark ile ölçülmelidir. Disk, network ve CPU bottleneck birbirinden ayrılmalıdır. Memory artışına karşı elde edilen throughput kazanımı ekonomik olarak da değerlendirilmelidir.
Memory Consumption
Stream başına buffering küçük görünse bile binlerce concurrent connection toplamda büyük memory oluşturabilir. WebSocket ve SSE servislerinde connection sayısı özellikle önemlidir. Container memory budget buffer worst case üzerinden test edilmelidir. RSS ve external memory highWaterMark değişikliklerinden sonra karşılaştırılabilir. Peak footprint SLO içindeki headroom'u aşmamalıdır.
Varsayılan Değeri Körlemesine Artırmamak
Throughput düşük diye highWaterMark değerini doğrudan birkaç kat yükseltmek root cause'u çözmeyebilir. Bottleneck downstream API veya disk olabilir. Daha büyük buffer yalnız daha fazla veriyi RAM'de bekletir. Önce profiler ve I/O metric ile dar boğaz belirlenmelidir. Sonra küçük kontrollü adımlarla benchmark yapılmalıdır.
Benchmark ile Belirlemek
Aynı workload farklı highWaterMark değerleriyle tekrarlanabilir. Throughput, P99 latency, RSS ve CPU birlikte kaydedilir. Warm-up süresi ve concurrency her deneyde aynı olmalıdır. Sonuç tek request üzerinden değil uzun enough load test üzerinden değerlendirilmelidir. En hızlı değer yerine SLO ve memory budget içinde en dengeli değer seçilmelidir.
Büyük JSON Verilerinde Memory Yönetimi
JSON parse ve stringify işlemleri büyük payload'larda önemli transient allocation oluşturabilir. Serialized string ile parsed object graph aynı anda memory'de bulunduğunda peak footprint beklenenden yüksek olabilir. Büyük API response oluştururken object ve JSON string kopyası aynı anda tutulabilir. Pagination, streaming format veya NDJSON bu riski azaltabilir. Request ve response boyutları server-side limitlerle sınırlandırılmalıdır.
JSON.parse() Allocation Spike
`JSON.parse()` büyük string'i JavaScript object graph'a dönüştürür. Parse sırasında source string bir süre memory'de kalırken yeni object'ler oluşturulur. Çok büyük payload ve concurrency birlikte heap spike oluşturabilir. Body size limiti bu nedenle security kadar memory control aracıdır. Gerçek payload dağılımı production metric olarak izlenmelidir.
JSON.stringify() Allocation Spike
`JSON.stringify()` büyük object graph'ı yeni string representation'a dönüştürür. Original object ve serialized string aynı anda memory'de bulunabilir. Response compression ek Buffer allocation da oluşturabilir. Çok büyük response page veya stream formatına bölünmelidir. Peak heap benchmark response serialization aşamasını içermelidir.
Büyük Request Body
Client'ın onlarca megabyte JSON göndermesine izin vermek her concurrent request için yüksek allocation oluşturur. Parser body tamamlanana kadar veriyi bufferlayabilir. Server body limit business requirement'a göre belirlenmelidir. Limit aşımı erken ve kontrollü response ile sonlandırılmalıdır. Bulk import için file streaming veya asynchronous job API daha uygun olabilir.
Büyük API Response
Tek response içinde yüz binlerce record döndürmek server ve client için aynı anda problem yaratır. Database result, mapped DTO ve serialized JSON ayrı allocation aşamaları oluşturabilir. Pagination hem memory hem network latency'yi sınırlar. Export endpoint normal API response modelinden ayrılmalıdır. Büyük export stream veya background file generation ile yapılabilir.
JSON Streaming
JSON streaming data'yı parça parça üretip tüketmeyi amaçlar. Standart tek JSON document yapısı streaming için ek syntax yönetimi gerektirebilir. Library seçimi backpressure desteği açısından değerlendirilmelidir. Parser malformed input durumunda resource cleanup yapmalıdır. Streaming format client contract'ı ile birlikte tasarlanmalıdır.
NDJSON
NDJSON her satırda bağımsız JSON object taşıdığı için incremental processing için pratiktir. Producer bütün array'i memory'de oluşturmak zorunda kalmaz. Consumer line bazında parse edip önceki record'u bırakabilir. Malformed line için error policy tanımlanmalıdır. Export ve event archive gibi use case'lerde memory-efficient seçenek olabilir.
Pagination
Pagination response object sayısını request başına sınırlar. Server maksimum page size zorunlu kılmalıdır. Client daha büyük limit gönderse bile kabul edilmemelidir. Cursor pagination büyük ve değişken dataset'lerde avantaj sağlayabilir. Page size load test ile heap ve latency etkisine göre belirlenmelidir.
HTTP Request Body Limitleri
HTTP body limitleri yalnız güvenlik kontrolü değil doğrudan memory budget kontrolüdür. JSON parser, form parser ve multipart handler farklı buffering davranışlarına sahip olabilir. Client'ın sınırsız body göndermesine izin vermek memory DoS riskini artırır. Upload dosyaları mümkün olduğunca RAM yerine stream üzerinden target storage'a aktarılmalıdır. Limit aşımları gözlemlenmeli ve gerçek business ihtiyacı olan endpoint'ler özel configuration almalıdır.
JSON Body Limit
JSON body maximum size framework veya parser seviyesinde açıkça ayarlanmalıdır. Default değere güvenmek business requirement'ı ifade etmez. Büyük bulk endpoint gerekiyorsa normal API limitinden ayrı tutulabilir. Limit aşıldığında parser mümkün olduğunca erken request'i durdurmalıdır. Metric olarak rejected body size count tutulabilir.
Form Body Limit
URL encoded form payload'ları da sınırsız olmamalıdır. Çok sayıda field parse işlemi CPU ve memory tüketebilir. Field count ve body byte limit birlikte değerlendirilebilir. Public endpoint'lerde abuse riskine karşı rate limit de uygulanmalıdır. Form data ihtiyaçları JSON API'den farklı olabilir.
Multipart Upload
Multipart parser dosya ve field bölümlerini işler. Library default olarak file'ı RAM'e bufferlıyorsa büyük upload ciddi risk oluşturur. Stream-to-disk veya object storage yaklaşımı tercih edilmelidir. File count, field count ve maximum size ayrı limitlenebilir. Incomplete upload temporary file cleanup test edilmelidir.
Dosyayı RAM Yerine Stream Etmek
Stream yaklaşımı file byte'larını küçük chunk'lar hâlinde taşır. Peak memory dosya boyutundan büyük ölçüde bağımsız tutulabilir. Backpressure destination hızına göre source'u yavaşlatır. Hash veya virus scan gerekiyorsa transform stream zincirine eklenebilir. Failure durumunda upload target ve stream kaynakları temizlenmelidir.
Memory DoS Riski
Attacker çok sayıda büyük request'i aynı anda açarak process memory'yi tüketmeye çalışabilir. Body limit tek request'i sınırlar fakat concurrency ve request rate de kontrol edilmelidir. Slow body upload connection resource'larını uzun süre tutabilir. Reverse proxy ve application timeout birlikte tasarlanmalıdır. OOM security incident olarak da değerlendirilmeli ve alert üretmelidir.
Promise.all() ve Kontrolsüz Paralellik
`Promise.all()` verilen bütün operation'ları aynı anda başlatmayı kolaylaştırır fakat input listesi büyükse concurrency kontrolü ortadan kalkar. Her Promise closure, network socket, query result veya Buffer tutabilir. Binlerce operation aynı anda başladığında heap, connection pool ve downstream service birlikte baskı altına girer. Bounded concurrency daha öngörülebilir resource kullanımı sağlar. Batch, semaphore veya worker queue pattern'leri bu nedenle kurumsal backend'lerde sık tercih edilir.
Binlerce Promise'i Aynı Anda Oluşturmak
On bin item üzerinde doğrudan `Promise.all(items.map(...))` her item için operation state oluşturabilir. Downstream database yalnız 20 connection çalıştırabiliyorsa geri kalan Promise'ler zaten queue'da bekleyecektir. Bu bekleyen state memory kullanır. Concurrency limit gerçek dependency capacity'ye yakın tutulmalıdır. Load test item count üst sınırlarını temsil etmelidir.
Promise Başına Retained State
Her Promise callback input object'ini closure içinde tutabilir. Input büyükse binlerce pending Promise toplam retained memory'yi hızla büyütür. Yalnız ID veya küçük payload capture etmek footprint'i azaltır. Operation tamamlandıkça state'in bırakıldığı doğrulanmalıdır. Heap allocation profile concurrency artışının etkisini gösterebilir.
Büyük Array of Results
`Promise.all()` bütün sonuçları aynı array içinde toplar. Her result büyükse operation'lar tamamlanmış olsa bile final array memory'de kalır. Sonuçlar sırayla işlenebiliyorsa streaming veya batch aggregation daha uygundur. Export pipeline intermediate result array oluşturmamalıdır. Result memory budget input concurrency kadar planlanmalıdır.
Concurrency Limiting
Concurrency limiting aynı anda çalışabilecek Promise sayısına üst sınır getirir. Limit database pool, API rate limit ve process memory üzerinden seçilir. Sabit limit başlangıç için yeterli olabilir. Daha gelişmiş sistemde queue depth ve latency üzerinden adaptive davranış düşünülebilir. Ancak control logic'in kendisi basit ve gözlemlenebilir tutulmalıdır.
Batch Processing
Input küçük batch'lere bölünür ve her batch tamamlandıktan sonra sonraki başlatılır. Batch sonucu persist edildikten sonra reference bırakılabilir. Bu yöntem peak memory'yi düşürür. Batch size çok küçükse throughput düşebilir. Benchmark ile memory ve throughput dengesi bulunmalıdır.
Worker Queue
Worker queue belirli sayıda consumer'ın pending işleri sırayla almasını sağlar. Queue'nun kendisi de bounded olmalıdır. Producer çok hızlıysa backpressure veya load shedding uygulanmalıdır. External queue restart dayanıklılığı ve cross-process scale sağlar. Queue depth ve oldest message age production metric olarak izlenmelidir.
Kurumsal Node.js'te Concurrency Nasıl Sınırlandırılır?
Concurrency limit yalnız performans optimizasyonu değil memory ve dependency koruma mekanizmasıdır. Aynı anda kaç database query, file transform veya HTTP request çalışabileceği belirli bir bütçeye bağlanmalıdır. Semaphore ve worker pool gibi pattern'ler aktif operation sayısını sınırlar. Bekleyen queue da sınırsız bırakılmamalıdır. En iyi limit benchmark, downstream kapasite ve latency SLO sonuçlarına göre seçilir.
Semaphore
Semaphore belirli sayıda permit üzerinden aynı anda çalışabilecek operation sayısını sınırlar. Operation başlamadan permit alır ve `finally` içinde geri bırakır. Permit release unutulursa deadlock benzeri capacity kaybı oluşabilir. Timeout ile bekleyen acquisition'lar sınırlandırılabilir. Active permit ve waiting count metrics olarak izlenebilir.
Worker Pool
Worker pool belirli sayıda işçiyle task'ları işler. CPU-bound işler Worker Threads pool üzerinden yürütülebilir. I/O-bound işlerde Promise concurrency pool yeterli olabilir. Pool boyutu CPU yanında worker heap memory maliyetiyle de hesaplanmalıdır. Queue depth pool saturation'ı gösteren önemli sinyaldir.
Queue
Queue producer ile consumer hızını ayırır. Ancak sınırsız queue memory pressure'ı yalnız başka yere taşır. Maximum depth ve overflow policy tanımlanmalıdır. Queue dolduğunda request reject etmek sistemin tamamının OOM olmasından daha sağlıklı olabilir. External queue durability ve replay gerektiren workload'larda tercih edilir.
p-limit Benzeri Yaklaşımlar
Küçük application'larda concurrency limiter abstraction kullanmak kolay ve okunabilir çözüm sağlar. Aynı anda yalnız belirli sayıda Promise çalıştırılır. Library güncel Node.js sürümü ve project dependency policy ile uyumlu olmalıdır. Çok basit ihtiyaç için custom semaphore da yazılabilir. Seçimden bağımsız olarak concurrency değeri configuration ve metric üzerinden görünür olmalıdır.
Batch Size
Batch size aynı anda memory'de tutulacak data miktarını doğrudan etkiler. Büyük batch throughput'u artırabilir fakat heap spike oluşturabilir. Küçük batch daha fazla round trip ve overhead yaratır. Production benzeri input distribution ile birkaç değer karşılaştırılmalıdır. Batch size endpoint veya job type'a göre farklı olabilir.
Backpressure
Backpressure producer'ın queue kapasitesine göre yavaşlamasını sağlar. Queue dolduğunda yeni work kabul edilmemeli veya upstream'e gecikme sinyali verilmelidir. HTTP'de hızlı rejection, stream'de pause ve message broker'da consumer flow control farklı mekanizmalardır. Amaç aynı, memory'de sınırsız pending state oluşmasını engellemektir. Backpressure davranışı overload testinde doğrulanmalıdır.
In-Memory Queue Kullanmanın Riskleri
In-memory queue düşük latency ve basitlik sunar ancak process memory ile sınırlıdır. Process crash olduğunda queued işler kaybolabilir ve producer consumer'dan hızlıysa queue sınırsız büyüyebilir. Bu yapı küçük, geçici ve bounded workload için uygundur. Kritik veya büyük iş akışlarında external queue daha güvenli olabilir. Queue seçiminde durability kadar memory budget ve overload davranışı da değerlendirilmelidir.
Queue'nun Sınırsız Büyümesi
Her yeni job bir object ve çoğu zaman payload reference'ı ekler. Consumer throughput düşük kaldığında pending count sürekli yükselir. Bu klasik leak olmadan OOM oluşturabilir. Maximum queue length ve byte budget belirlenmelidir. Queue growth rate alert'i overload'u erken gösterebilir.
Producer Consumer Dengesizliği
Producer saniyede bin job eklerken consumer yalnız 500 işliyorsa fark sürekli birikir. Kısa spike buffer ile absorbe edilebilir fakat sürekli fark architecture kapasite problemidir. Queue yalnız semptomu geciktirir. Consumer scale, upstream rate veya iş maliyeti yeniden değerlendirilmelidir. Queue age metriği kullanıcı gecikmesini doğrudan gösterir.
Queue Limit
Queue limit maksimum pending job sayısını belirler. Limit dolduğunda drop, reject veya upstream backpressure policy uygulanabilir. Critical job'lar için drop uygun olmayabilir ve external durable queue gerekir. Limit memory benchmark üzerinden seçilmelidir. Queue capacity configuration değişikliği gözlemlenebilir ve versioned olmalıdır.
Load Shedding
Load shedding sistem kapasitesini aşan yeni işi bilinçli olarak reddeder. Kısa süreli 503 response bütün process'in OOM olup dakikalarca unavailable kalmasından daha iyi olabilir. Priority request'ler farklı queue kullanabilir. Rejection rate alarm ve capacity planning girdisi olur. Client retry davranışı exponential backoff ile uyumlu olmalıdır.
External Queue
External queue pending işleri process heap dışında tutar ve application restart'ından bağımsız dayanıklılık sağlayabilir. Bunun karşılığında network, serialization ve broker operasyon maliyeti gelir. Consumer prefetch veya batch ayarı yine memory kullanımını etkiler. Broker kullanmak sınırsız consumer memory sorununu otomatik çözmez. Worker concurrency ve message size hâlâ sınırlandırılmalıdır.
Redis / Kafka / RabbitMQ
Redis, Kafka veya RabbitMQ farklı queue ve messaging gereksinimleri için kullanılabilir. Seçim delivery semantics, ordering, throughput ve operasyon deneyimine göre yapılmalıdır. Node.js consumer yalnız işleyebileceği kadar message almalıdır. Large message payload yerine object storage reference kullanmak memory ve broker maliyetini azaltabilir. Event-driven backend tasarımına ilişkin ek örnekler için https://www.diyarbakiryazilim.com.tr/posts/backend-sistemlerinde-event-driven-olay-gudumlu-iletisim içeriği de incelenebilir.
WebSocket ve SSE Bellek Yönetimi
WebSocket ve Server-Sent Events bağlantıları klasik kısa HTTP request'lerinden çok daha uzun süre yaşar. Her connection socket state, listener, heartbeat timer ve outbound queue taşıyabilir. On binlerce bağlantıda connection başına birkaç kilobyte fark bile toplam RSS'i önemli ölçüde değiştirir. Slow consumer'lar server tarafında buffered message birikmesine yol açabilir. Connection cleanup ve per connection quota bu nedenle architecture seviyesinde tasarlanmalıdır.
Connection Başına Memory
Her connection'ın baseline memory footprint'i load test ile ölçülebilir. Bir, bin ve on bin idle connection arasındaki RSS farkı yaklaşık capacity plan verir. Authentication context ve room membership bu footprint'e eklenir. Büyük user object yerine küçük identifier tutulmalıdır. Maximum concurrent connection container memory budget üzerinden hesaplanmalıdır.
Socket State
Socket object üzerinde gereksiz büyük business state saklanmamalıdır. Connection için user ID, subscription listesi ve minimal protocol state yeterli olabilir. Full profile veya large history external store'da tutulabilir. Socket close olduğunda state collection'dan kaldırılmalıdır. Stale socket sayısı metric olarak izlenebilir.
Event Listener
Her connection birkaç listener ekler ve bu normaldir. Problem disconnect sonrası listener'ların shared emitter üzerinde kalmasıdır. Listener count active connection sayısıyla yaklaşık orantılı olmalıdır. Close cleanup sonrası sayı düşmelidir. Soak test connection churn altında bu davranışı doğrular.
Message Queue
Slow client'a gönderilecek mesajlar memory'de queue edilirse limit zorunludur. Queue byte size connection başına ölçülebilir. Limit aşıldığında eski mesaj drop, connection close veya resync policy uygulanabilir. Business correctness hangi seçeneğin uygun olduğunu belirler. Sınırsız queue tüm process'i tek bir yavaş client nedeniyle riske atmamalıdır.
Slow Consumer
Slow consumer network veya device nedeniyle server'ın üretim hızına yetişemez. Backpressure sinyali dikkate alınmazsa outbound buffer büyür. Connection başına maximum buffered bytes uygulanmalıdır. Sürekli yavaş client kontrollü şekilde disconnect edilebilir. Metric olarak slow consumer count operasyon ekibine kapasite sinyali verir.
Connection Cleanup
Disconnect sırasında timer, room membership, listener ve queue temizlenmelidir. Cleanup normal close, error ve timeout yollarında aynı function üzerinden çalışabilir. Idempotent cleanup double event durumunda güvenlidir. Stale connection collection'ları leak'in sık nedenidir. Integration test zorla socket close ederek cleanup sonucunu kontrol etmelidir.
Heartbeat
Heartbeat kopmuş fakat TCP seviyesinde hemen fark edilmeyen connection'ları tespit etmeye yardımcı olur. Per connection timer yerine merkezi scheduler bazı sistemlerde daha az overhead oluşturabilir. Heartbeat interval çok kısa olursa network ve CPU yükü artar. Timeout sonrası cleanup bütün state'i serbest bırakmalıdır. Heartbeat metric active connection sağlığı hakkında ek bilgi sağlar.
Per-Tenant Memory Growth Nasıl Önlenir?
Multi tenant uygulamalarda toplam memory güvenli görünürken tek büyük tenant process bütçesinin önemli kısmını tüketebilir. Tenant başına cache, connection veya WebSocket sayısı bu riski oluşturur. Quota ve bounded resource politikaları noisy neighbor etkisini azaltır. Tenant ID high-cardinality olduğu için her tenant'ı Prometheus label yapmak yerine top consumer telemetry veya log analizi kullanılabilir. Büyük tenant'lar için dedicated worker veya farklı deployment modeli de değerlendirilebilir.
Tenant Başına Cache
Her tenant için ayrı Map oluşturmak tenant sayısı ve data cardinality ile memory'yi çarpabilir. Global maximum yanında per tenant maximum da belirlenmelidir. Inactive tenant cache'i TTL ile temizlenebilir. Whale tenant tüm cache capacity'yi işgal etmemelidir. Cache key ve eviction policy multi tenant fairness'i hesaba katmalıdır.
Tenant Başına Connection
Her tenant'a ayrı database pool oluşturmak yüzlerce tenant'ta connection ve memory patlamasına yol açabilir. Shared pool veya bounded pool registry daha uygun olabilir. Tenant-specific database zorunluysa inactive pool TTL ile kapatılabilir. Open pool count metriği izlenmelidir. Pool creation concurrency de sınırlandırılmalıdır.
Tenant Başına WebSocket
Büyük tenant binlerce active socket ile diğer tenant'ların capacity'sini tüketebilir. Per tenant connection quota adil kullanım sağlar. Premium plan farklı quota alabilir ancak toplam process budget korunmalıdır. Connection memory ve outbound queue ayrı limitlenmelidir. Tenant-specific overload hızlı ve anlaşılır error ile yönetilmelidir.
Tenant Memory Quota
JavaScript process içinde gerçek byte bazlı per tenant heap quota uygulamak kolay değildir. Buna rağmen cache size, queue depth ve active connection gibi proxy limitler kullanılabilir. Her tenant'ın high-cost resource'ları ölçülür. Quota aşımı load shedding veya externalization tetikleyebilir. Architecture shared heap'in tek tenant tarafından tüketilmesini önlemeyi hedeflemelidir.
Whale Tenant
Whale tenant normal tenant'tan çok daha fazla trafik veya data üreten müşteridir. Average workload'a göre sizing bu tenant geldiğinde bozulabilir. Capacity test yüksek percentile tenant davranışını simüle etmelidir. Gerekirse tenant dedicated shard veya deployment'a taşınabilir. Pricing ve quota policy teknik resource maliyetiyle uyumlu olmalıdır.
Noisy Neighbor
Noisy neighbor bir tenant'ın resource kullanımının diğer kullanıcıların latency veya availability'sini bozmasıdır. Memory, CPU, connection ve queue limitleri bu etkiyi azaltır. Per tenant concurrency limiting uygulanabilir. Monitoring top resource consumer'ları görünür kılmalıdır. Isolation architecture business importance'a göre process, pod veya cluster seviyesine kadar çıkabilir.
Node.js Heap Limit Nedir?
Node.js process V8 heap için sınırsız memory kullanmaz. V8 runtime platform, sürüm ve runtime koşullarına göre heap size limit belirler. Bu limit container memory limitinin tamamı değildir çünkü process native memory, Buffer ve stack için de RAM kullanır. Uygulama startup sırasında gerçek heap limitini `v8.getHeapStatistics()` ile ölçebilir. Hard coded internetteki eski bir “Node.js heap limiti şu kadardır” değerine güvenmek yerine kullanılan runtime üzerinde ölçüm yapmak daha güvenlidir.
V8 Heap Limit
V8 heap limit JavaScript managed heap'in maksimum büyüklüğünü sınırlar. Limit yaklaştığında garbage collector daha fazla efor harcayabilir. Live object set limitten büyükse process JavaScript heap out of memory ile kapanabilir. Heap limit container limitinden daha düşük veya farklı olabilir. Memory budget ikisini bağımsız değişkenler olarak ele almalıdır.
Old Space
`--max-old-space-size` esas olarak V8 old memory section için maximum size belirler. Uzun ömürlü object'ler ve promoted data burada önemli yer tutar. Flag toplam process RSS limitini belirlemez. Buffer ve native allocation'lar bu limitin dışında memory tüketmeye devam edebilir. Bu nedenle flag değeri container RAM'inin tamamına eşitlenmemelidir.
Heap Limitin Node.js Sürümüne Göre Değişebilmesi
Node.js her major sürümde farklı V8 sürümü taşır ve memory heuristics zamanla değişebilir. Architecture ve platform da default limit davranışını etkileyebilir. Bu nedenle eski blog yazılarındaki sabit heap sayıları production policy olmamalıdır. Upgrade öncesi `v8.getHeapStatistics().heap_size_limit` karşılaştırılabilir. Memory benchmark yeni runtime ile tekrar çalıştırılmalıdır.
Default Değere Güvenmemek
Default heap limit bare metal ve container deployment'ın gerçek memory budget'ıyla her zaman uyumlu olmayabilir. Container limiti düşükse process V8 limitine ulaşmadan kernel OOM yaşayabilir. Yüksek memory container'da ise default değer workload için gereksiz küçük olabilir. Runtime heap limiti startup log veya metric olarak kaydedilmelidir. Explicit tuning yalnız measurement sonrasında yapılmalıdır.
Runtime'da Heap Limitini Ölçmek
`v8.getHeapStatistics()` içindeki `heap_size_limit` değeri runtime'ın mevcut heap limitini gözlemlemek için kullanılabilir. Bu değer byte cinsinden metric'e çevrilebilir. Deployment sonrası gerçekten beklenen flag'in uygulandığı doğrulanabilir. Configuration drift böylece erken görülür. Metric container limit ile aynı dashboard'da gösterilirse headroom anlaşılır hâle gelir.
--max-old-space-size Nasıl Kullanılır?
`--max-old-space-size` V8 old memory section için maksimum memory boyutunu MiB cinsinden ayarlayan runtime flag'idir. Değer yükseldikçe application daha büyük canlı heap taşıyabilir. Buna karşılık process'in native memory ve Buffer için kullanacağı alan ayrıca kalır. Heap limitini artırmak gerçek memory leak'i ortadan kaldırmaz, yalnız failure noktasını ileri taşır. Değer production container memory budget ve GC benchmark sonucuna göre seçilmelidir.
MiB Olarak Heap Limiti
Flag örneğin `node --max-old-space-size=1536 app.js` biçiminde kullanılabilir. Girilen değer MiB cinsindedir. Container 2 GiB ise tüm 2 GiB'ı heap'e vermek güvenli değildir. Node.js runtime ve native memory için pay bırakılmalıdır. Startup metric gerçek applied heap limitini doğrulamalıdır.
Heap'i Artırmak Ne Zaman Mantıklıdır?
Uygulamanın gerçekten büyük fakat bounded live dataset tutması gerekiyorsa daha büyük heap anlamlı olabilir. Büyük compile, data processing veya memory cache workload buna örnektir. Önce leak olmadığı snapshot ve soak test ile doğrulanmalıdır. GC frequency ve P99 latency yeni limitte tekrar ölçülmelidir. Container limit aynı kaldığında heap artışı native headroom'u azaltmamalıdır.
Heap'i Artırmak Memory Leak'i Çözer mi?
Hayır, unbounded reference growth varsa daha büyük heap yalnız OOM anını geciktirir. Leak rate aynı kalırsa process sonunda yeni limite de ulaşır. Bu gecikme incident'ın daha seyrek görünmesine neden olabilir ve root cause'u saklayabilir. Önce retaining path bulunup reference lifecycle düzeltilmelidir. Heap artırımı ancak fix sonrası gerçek workload için gerekli capacity varsa ayrı optimizasyon olarak yapılmalıdır.
Büyük Heap'in GC Pause Etkisi
Daha büyük heap collector'a daha geniş canlı object alanı bırakabilir. Major GC bazı workload'larda daha uzun sürebilir. Bunun kesin etkisi uygulama allocation profile'ına bağlıdır. Bu nedenle heap tuning yalnız OOM sonucu üzerinden değerlendirilmemelidir. GC duration ve P99 latency yeni limitte benchmark edilmelidir.
--max-old-space-size-percentage Nedir?
Güncel Node.js sürümlerinde `--max-old-space-size-percentage` V8 old memory alanını kullanılabilir sistem belleğinin belirli yüzdesine göre ayarlamayı sağlar. Aynı anda `--max-old-space-size` verilirse percentage flag önceliklidir. Dinamik memory boyutuna sahip bazı deployment modellerinde sabit MiB değeri yerine yüzdesel yaklaşım yararlı olabilir. Yine de yüzde 100 seçmek doğru değildir çünkü process heap dışı memory kullanır. Container ve runtime'ın “available system memory” algısı deployment ortamında doğrulanmalıdır.
Sistem Belleğinin Yüzdesi
Flag 0'dan büyük ve 100'e kadar percentage kabul eder. Örneğin 50 değeri available memory'nin yarısı üzerinden old space limiti oluşturur. Bu davranış process RSS'in yüzde 50'de kalacağını garanti etmez. Native memory ve Buffer ek olarak tüketilir. Percentage değeri memory budget hesaplandıktan sonra seçilmelidir.
Dinamik Ortamlarda Kullanım
Aynı container image farklı memory sınıflarında deploy ediliyorsa yüzdesel ayar configuration yönetimini kolaylaştırabilir. Bununla birlikte farklı workload'lar aynı percentage ile optimum davranmayabilir. Heap size limit metric'i her instance'ta kontrol edilmelidir. Canary deployment yeni setting'in GC ve RSS etkisini doğrular. Sabit environment-specific değer bazı sistemlerde daha öngörülebilir olabilir.
Container Kullanımında Dikkat Edilecek Noktalar
Container runtime ve Node.js sürümünün memory limit algısı test edilmelidir. Flag'in hesapladığı heap limit cgroup limitine göre beklenen sonucu vermiyorsa explicit MiB ayarı tercih edilebilir. Container memory limit ayrıca sidecar ve tmpfs kullanımından etkilenebilir. Process RSS'e safety margin bırakılmalıdır. OOM event'leri rollout sırasında yakından izlenmelidir.
OS ve Native Bellek İçin Headroom
Heap container limitinin tamamını kullanırsa Buffer veya TLS allocation için yer kalmaz. GC ve snapshot gibi diagnostic operasyonlar da geçici ek memory isteyebilir. Headroom miktarı workload'a göre benchmark edilmelidir. Buffer-heavy servis ile pure JSON API aynı ratio'yu kullanmak zorunda değildir. Memory SLO minimum headroom yüzdesini de içerebilir.
Node.js İçin Memory Budget Nasıl Oluşturulur?
Memory budget process'in hangi component için ne kadar RAM kullanabileceğini deployment öncesinde tanımlar. Başlangıç noktası container veya VM memory limitidir. Bunun içinden V8 heap, external Buffer, native memory, worker ve runtime overhead için pay ayrılır. Peak traffic ve diagnostic operation'lar için safety margin bırakılır. Budget gerçek metric'lerle birkaç production cycle sonunda güncellenmelidir.
Container Memory Limit
Container limit process için mutlak üst sınıra yakın bir sınır oluşturur. Kubernetes memory limit kernel cgroup mekanizmasıyla enforce edilir ve aşım OOM kill ile sonuçlanabilir. Limit average RSS'e göre değil peak ve burst davranışına göre belirlenmelidir. Sidecar aynı pod içinde ayrı container limitine sahip olabilir. Pod toplam memory capacity planning ayrıca yapılmalıdır.
V8 Heap
V8 heap memory budget'ın yalnız bir bölümüdür. Runtime ölçülen `heap_size_limit` deployment manifest ile uyumlu olmalıdır. Normal peak heap kullanımının limitin sürekli çok yakınına gelmemesi gerekir. GC sonrası baseline ayrıca izlenir. Heap headroom yüksek allocation burst'leri için alan sağlar.
Native Memory
TLS, compression, database driver ve native addon gibi component'ler native memory tüketebilir. Bu değer tamamen önceden hesaplanamayabilir. Staging load test RSS eksi heap ve external farkı hakkında yaklaşık bilgi verir. Native workload değiştiğinde budget revize edilir. Yeni native dependency release öncesi memory regression testine dahil edilmelidir.
Buffers
File veya network-heavy service'lerde Buffer memory önemli pay alabilir. `arrayBuffers` ve `external` metriği typical ve peak kullanımı gösterir. Maximum payload ve concurrency üzerinden worst case hesaplanabilir. Stream adoption bu bütçeyi azaltabilir. Buffer queue'ları bounded olduğunda peak daha öngörülebilir olur.
Thread Stack
Worker Threads ve native thread pool ek stack memory kullanır. Çok sayıda worker process RSS'ini beklenenden fazla artırabilir. Worker başına memory benchmark yapılmalıdır. Worker resource limits yalnız JavaScript heap alanlarının bir kısmını sınırlar ve tüm process memory'sini sınırlamaz. Pool size CPU ve memory birlikte düşünülerek belirlenmelidir.
Runtime Overhead
Node.js runtime, loaded code, shared libraries ve framework object'leri uygulama payload'ından bağımsız baseline memory oluşturur. Boş application ve warmed application arasındaki fark ölçülebilir. Bu overhead container sizing'de unutulmamalıdır. APM agent eklenmesi baseline'ı değiştirebilir. Her büyük dependency veya instrumentation değişikliği sonrası yeniden ölçüm yapılmalıdır.
Safety Margin
Safety margin traffic spike, allocator davranışı ve kısa süreli diagnostic allocation için boş alan bırakır. Container limit ile normal peak RSS arasında anlamlı fark bulunmalıdır. Margin çok düşükse küçük Buffer burst OOM oluşturabilir. Çok yüksek margin ise infrastructure utilization'ı düşürür. Değer canary ve load test sonuçlarıyla dengelenmelidir.
Docker İçinde Node.js Memory Yönetimi
Docker container memory limiti Node.js process'in kullanabileceği toplam kaynak için sınır oluşturur. V8 heap limiti ile container limiti aynı kavram değildir. Process RSS container limitine yaklaşırsa kernel OOM davranışı devreye girebilir. Heap normal görünürken native veya Buffer memory nedeniyle container yine kapanabilir. Docker deployment'ta process ve cgroup memory metrics aynı panelde izlenmelidir.
Container Memory Limit
Docker `--memory` gibi seçeneklerle container memory sınırı belirlenebilir. Limit olmayan container host memory üzerinde daha geniş etkiye sahip olabilir. Production'da açık resource budget tercih edilmelidir. Node heap setting bu sınırın altında yeterli headroom bırakmalıdır. Limit değeri application benchmark ve host scheduling planıyla uyumlu olmalıdır.
RSS
RSS process memory footprint'i için temel göstergedir. Container cgroup usage ile birebir aynı olmak zorunda değildir çünkü page cache ve başka container memory kategorileri de olabilir. Yine de Node process için önemli başlangıç metriğidir. RSS limit yüzdesi alarm olarak izlenebilir. HeapUsed ile fark büyüdüğünde external ve native alanlar araştırılmalıdır.
V8 Heap Limit
V8 heap limit process içinde JavaScript memory'nin büyümesini sınırlar. Container limit otomatik olarak güvenli heap budget anlamına gelmez. Startup sırasında heap size limit metric'e alınmalıdır. Image farklı memory limitli environment'larda çalışıyorsa setting doğrulanmalıdır. Heap limit değişikliği load test olmadan rollout edilmemelidir.
OOM
Container memory limit aşımı kernel tarafından process'in öldürülmesine yol açabilir. Bu durum JavaScript tarafından catch edilebilecek normal exception gibi ele alınamaz. Exit veya container state OOM sinyali üzerinden tespit edilir. Diagnostic report fatal error için yardımcı olabilir ancak kernel kill anında her zaman artifact üretme fırsatı olmayabilir. Headroom ve early alert bu nedenle daha değerlidir.
Docker Memory Metrics
Container runtime cgroup memory kullanımı, limit ve OOM event bilgisi sağlayabilir. Application metric'leriyle aynı time series dashboard'da birleştirilmelidir. RSS ile container usage arasındaki fark analiz edilebilir. Restart sonrası memory sıfırlandığı için long-term leak grafiği restart event ile birlikte okunmalıdır. Deployment version annotation regression başlangıç noktasını bulmayı kolaylaştırır.
Heap İçin Tüm Container RAM'ini Ayırmamak
Node.js process heap dışında da memory kullanır. Buffer, native library, code ve thread stack'leri için alan gerekir. Heap limitini container memory limitine eşitlemek kernel OOM riskini artırır. Diagnostic snapshot sırasında geçici memory kullanımı daha da büyüyebilir. Production budget normal peak yanında failure investigation ihtiyaçlarını da hesaba katmalıdır.
Kubernetes'te Node.js Bellek Yönetimi
Kubernetes scheduling için memory request, runtime enforcement için memory limit kavramlarını kullanır. Request scheduler'ın pod yerleştirme kararına katkıda bulunurken limit Linux ortamında cgroup mekanizmalarıyla enforce edilir. Memory limit aşımı CPU limitinden farklı olarak throttling yerine OOM kill ile sonuçlanabilir. Pod QoS sınıfı node memory pressure durumunda davranışı etkileyebilir. Node.js heap ayarı bu orchestration seviyesinden bağımsız bırakılmamalıdır.
Memory Request
Memory request scheduler'a pod'un beklenen kaynak ihtiyacını bildirir. Node üzerinde yeterli allocatable memory yoksa pod schedule edilmeyebilir. Request gerçek steady-state RSS'in çok altında seçilirse node aşırı dolabilir. Çok yüksek seçilirse cluster utilization düşer. P50 veya average yerine workload pattern ve QoS hedefi birlikte değerlendirilmelidir.
Memory Limit
Memory limit container'ın kullanabileceği memory için üst sınır oluşturur. Linux kernel bu sınırı cgroup üzerinden uygular. Limit aşımı durumunda process OOM kill yaşayabilir. Node.js heap limiti limitin altında safety margin bırakacak şekilde ayarlanmalıdır. Limit canary gözlemi ve load test ile doğrulanmalıdır.
Working Set
Working set metric container'ın aktif memory kullanımını anlamada yaygın şekilde kullanılır. Metric implementasyonu ve cache accounting monitoring stack'e göre farklı yorumlanabilir. Node process RSS ile birlikte değerlendirmek daha güvenlidir. Alert yalnız working set yüzdesine dayandırılmamalıdır. Heap ve external breakdown root cause'u anlamayı sağlar.
OOMKilled
Kubernetes container status içinde OOMKilled nedeni görülebilir. Bu olay process'in memory limitini veya node-level OOM koşullarını aşmasıyla ilişkili olabilir. Pod events ve previous container state incelenmelidir. Restart sonrası current memory normal görüneceği için incident öncesi telemetry korunmalıdır. OOM count reliability SLO içinde ayrı metric olmalıdır.
Pod Restart
Restart leak'in symptom'unu geçici olarak sıfırlar. Memory tekrar büyüyorsa interval restart root cause'u gizler. Buna rağmen emergency mitigation olarak worker recycling availability'yi koruyabilir. Restart rate alarmı deployment regression'ını hızlı gösterir. Root cause analysis tamamlanmadan restart policy “çözüm” olarak kabul edilmemelidir.
QoS Class
Kubernetes QoS sınıfları request ve limit configuration'ına göre pod'ların resource pressure altındaki davranışını etkiler. Guaranteed, Burstable ve BestEffort sınıfları node OOM selection üzerinde farklı korunma seviyelerine sahip olabilir. Critical backend için request ve limit policy bilinçli seçilmelidir. QoS tek başına application memory leak'ini engellemez. Node pressure senaryoları chaos veya staging testlerinde gözlenebilir.
Node Memory Pressure
Node genelinde available memory düştüğünde kubelet eviction mekanizmaları devreye girebilir. MemoryPressure condition yeni scheduling davranışını da etkileyebilir. Uygulama kendi limitini aşmasa bile node contention nedeniyle risk yaşayabilir. Cluster-level monitoring application dashboard'a bağlantılı olmalıdır. Pod request sizing ve node reserved memory capacity planning'in parçasıdır.
OOMKilled Nedir?
OOMKilled container process'in memory baskısı nedeniyle operating system tarafından öldürüldüğünü gösteren yaygın Kubernetes durumudur. Bu olay V8'in kendi JavaScript heap out of memory hatasından farklı olabilir. Kernel process'i doğrudan sonlandırdığında uygulamanın graceful cleanup yapma fırsatı bulunmayabilir. Incident analizinde pod event, exit state, RSS, heapUsed ve container limit birlikte incelenmelidir. Tekrar eden OOMKilled olayları availability problemi olarak ele alınmalıdır.
V8 OOM ile Kernel OOM Arasındaki Fark
V8 OOM JavaScript heap limiti içinde allocation yapılamadığında ortaya çıkar. Kernel OOM ise process veya container toplam memory kullanımının sistem veya cgroup limitlerini zorlamasıyla gerçekleşebilir. Buffer-heavy uygulama V8 heap dolmadan kernel OOM yaşayabilir. Error log ve container state bu ayrımı yapmaya yardımcı olur. İki durumda uygulanacak root cause araçları farklı olabilir.
Exit Code
Container termination exit bilgisi incident'ın ilk ipucudur. OOM durumunda orchestration platformu termination reason ve exit code kaydedebilir. Ancak yalnız numeric code üzerinden conclusion verilmemelidir. Pod describe çıktısı ve runtime events birlikte incelenmelidir. Application graceful exit ile OOM exit birbirinden ayrılmalıdır.
Kubernetes Pod Events
Pod events scheduling, eviction ve container restart hakkında zaman çizgisi sağlar. OOMKilled reason previous container state içinde görülebilir. Node MemoryPressure veya eviction event'i ayrıca kontrol edilir. Events uzun süre saklanmayabileceği için merkezi incident telemetry değerlidir. Alert tetiklendiğinde otomatik context collection runbook'a eklenebilir.
Container Limit
OOM anındaki memory limit bilinmeden incident yorumlanmamalıdır. Deployment değişikliği limit değerini düşürmüş olabilir. Heap setting eski container limitine göre kaldıysa headroom kaybolabilir. Manifest ve runtime metric karşılaştırılmalıdır. Config change canary rollout ile gözlenmelidir.
RSS vs Heap
OOM öncesi RSS limitin yakınında fakat heapUsed düşükse native veya Buffer alanı araştırılır. HeapUsed da limitine yaklaşıyorsa JavaScript retention veya yüksek live set ihtimali artar. External ve arrayBuffers ek ayrım sağlar. GC logları heap pressure'ı gösterebilir. Bu multi metric yaklaşımı hızlı doğru araç seçimi sağlar.
Root Cause Analizi
İlk adım incident zaman aralığındaki deployment ve traffic değişikliklerini kontrol etmektir. Ardından heap, external, RSS ve restart grafikleri karşılaştırılır. Leak pattern varsa staging reproduction ve snapshot comparison yapılır. Native şüphede diagnostic report ve native profiler kullanılır. Fix sonrasında soak test ve canary aynı root cause'un kapandığını doğrular.
Memory Limit Aşıldığında Uygulama Nasıl Davranmalıdır?
Application hard OOM anını bekleyene kadar hiçbir şey yapmayan bir tasarıma sahip olmamalıdır. Memory kullanımı belirli güvenli eşiği uzun süre aşarsa readiness kapatılarak yeni trafik azaltılabilir. In-flight request'lere kısa drain süresi verilip controlled restart uygulanabilir. Bu mekanizma root cause çözümü değil blast radius azaltan emergency control'dür. Threshold ve shutdown davranışı chaos test ile doğrulanmalıdır.
Hard Crash'i Beklemek
Kernel OOM ani olabilir ve cleanup için fırsat bırakmayabilir. Active request'ler ve queue işi yarıda kalabilir. Tek replica sistemde downtime doğrudan kullanıcıya yansır. Bu nedenle sustained high memory için early alert ve traffic drain mekanizması faydalıdır. Yine de threshold çok düşük seçilirse gereksiz restart döngüsü oluşabilir.
Graceful Shutdown
Graceful shutdown yeni request kabulünü durdurup mevcut işlerin kontrollü tamamlanmasına izin verir. Database pool, queue consumer ve timer'lar kapatılır. Belirli timeout sonrası process sonlandırılır. Leak durumunda shutdown memory'yi düzeltmez ancak service availability'yi koruyabilir. Restart nedeni metric ve log olarak kaydedilmelidir.
Readiness'i Kapatmak
Kubernetes readiness false olduğunda service yeni trafik göndermeyi bırakabilir. Process drain sürecine geçmeden önce readiness kapatılmalıdır. Propagation gecikmesi nedeniyle kısa süre yeni request gelebileceği hesaba katılmalıdır. Liveness probe memory pressure nedeniyle process'i agresif biçimde öldürmemelidir. Readiness endpoint'in kendisi ağır dependency kullanmamalıdır.
Yeni Trafiği Durdurmak
Yeni trafik kesildiğinde active memory'nin düşüp düşmediği teşhis açısından da faydalıdır. Trafik durmasına rağmen heap baseline artmaya devam ediyorsa background leak ihtimali vardır. Queue consumer ayrıca durdurulmalıdır. Load balancer drain davranışı test edilmelidir. WebSocket gibi uzun connection'lar ayrı policy gerektirir.
In-Flight Requests
Graceful shutdown mevcut request'lere sınırlı tamamlanma süresi vermelidir. Sonsuz beklemek memory pressure altındaki process'in kurtulamamasına yol açar. Request deadline mevcutsa shutdown timeout onunla uyumlu olmalıdır. Idempotent operation retry edilebilir. Write operation'larda duplicate riskine karşı idempotency tasarlanmalıdır.
Process Restart
Restart process memory'yi operating system seviyesinde sıfırlar. Emergency mitigation olarak faydalıdır. Leak devam ediyorsa aynı growth pattern yeniden başlayacaktır. Restart frequency production metric olarak izlenmelidir. Planned recycling interval root cause araştırmasının yerine geçmemelidir.
Root Cause'u Restart ile Gizlememek
Sık restart memory graph'ını testere biçiminde göstererek leak baseline'ını gizleyebilir. Replica uptime ile peak memory arasında korelasyon aranmalıdır. Restart öncesi diagnostic metric'ler merkezi sistemde saklanmalıdır. Gerekirse bir replica kontrollü olarak daha uzun çalıştırılıp leak reproduce edilir. Fix yalnız restart interval uzadığı için başarılı kabul edilmemelidir.
Node.js Cluster Bellek Kullanımını Nasıl Etkiler?
Node.js cluster modelinde her worker ayrı process olduğu için her birinin kendi V8 heap'i vardır. Dört worker aynı application code'unu yüklediğinde toplam host memory tek process'in dört katına yaklaşabilir veya workload'a göre farklılaşabilir. CPU core sayısı kadar worker açmak memory budget izin vermiyorsa güvenli değildir. Worker başına baseline ve peak RSS ölçülmelidir. Host veya container toplam limit bu sayı üzerinden planlanmalıdır.
Process Başına Ayrı V8 Heap
Cluster worker'ları ayrı process'tir ve memory address space paylaşmaz. Her worker kendi garbage collector ve heap limitine sahiptir. Process-local cache worker'lar arasında duplicate olur. Büyük cache kullanılıyorsa worker sayısı memory maliyetini çarpar. Shared external cache bu duplication'ı azaltabilir.
N Worker × Memory
Capacity hesabında worker sayısı ile warmed RSS yaklaşık çarpılarak başlangıç tahmini yapılabilir. Gerçek değer shared library page accounting nedeniyle birebir olmayabilir. Peak concurrent workload worker'lar arasında farklı dağılım gösterebilir. Load test full worker count ile yapılmalıdır. Single worker benchmark toplam deployment memory'sini temsil etmez.
Shared Host Memory
Cluster process'leri aynı host veya container memory pool'unu paylaşır. Bir worker leak yaparsa diğer worker'lar için headroom azalır. Per process RSS metric gerekir. Worker restart yalnız problemli process'i recycle edebilir. Host-level OOM durumunda birden fazla process etkilenebilir.
Worker Sayısını CPU'ya Göre Körlemesine Belirlememek
CPU sayısı worker sizing için yalnız bir girdidir. Memory-heavy workload sekiz core host üzerinde sekiz worker için yeterli RAM bırakmayabilir. Database connection pool da worker sayısıyla çarpılır. Worker count load test sırasında throughput, RSS ve downstream capacity ile birlikte belirlenmelidir. Horizontal pod scaling bazı durumlarda cluster process sayısından daha kolay isolation sağlar.
Worker Başına Memory Budget
Her worker için heap, external ve RSS hedefi belirlenebilir. Total container limit worker count'a bölünürken master process ve safety margin unutulmamalıdır. Worker memory eşiği aşarsa kontrollü recycle uygulanabilir. Bu mekanizma leak fix yerine emergency protection'dır. Per worker telemetry root cause'un yalnız belirli traffic shard'da olup olmadığını gösterebilir.
Worker Threads Bellek Yönetimi
Worker Threads aynı process içinde ayrı V8 isolate kullanır. Her worker'ın JavaScript heap'i ayrı olabilir ancak process RSS bütün thread'lerin toplam etkisini gösterir. Büyük data structured clone ile worker'a gönderildiğinde kopyalama memory overhead'i oluşturabilir. Transferable ArrayBuffer veya SharedArrayBuffer uygun use case'lerde bu maliyeti azaltabilir. Worker sayısı CPU kadar memory ve task queue boyutuna göre de sınırlandırılmalıdır.
Ayrı V8 Isolate
Her Worker kendi V8 isolate'ı içinde JavaScript çalıştırır. Global object ve heap worker'lar arasında normal object reference ile paylaşılmaz. Bu isolation concurrency için yararlıdır ancak runtime overhead getirir. Worker başına module load ve cache duplicate olabilir. Pool tasarımında warm worker memory ölçülmelidir.
Worker Heap
Worker kendi heap statistics bilgisine sahiptir. Güncel Node.js Worker API worker heap snapshot ve heap statistics gibi observability imkanları sağlar. Main thread snapshot worker heap'i otomatik içermeyebilir. Leak yalnız belirli worker task'ında oluşuyorsa worker-specific snapshot gerekir. Worker recycling root cause testinde controlled mitigation olarak kullanılabilir.
RSS'in Process Genelini Göstermesi
`process.memoryUsage()` Worker Thread bağlamında kullanıldığında RSS process genelini temsil eder. Diğer bazı memory alanları yalnız current thread veya isolate açısından yorumlanır. Bu ayrım per worker dashboard tasarımında önemlidir. Main process RSS artışı hangi worker'ın suçlu olduğunu tek başına göstermez. Worker-specific heap statistics eklenmelidir.
SharedArrayBuffer
SharedArrayBuffer worker'lar arasında aynı underlying memory alanını paylaşmaya izin verir. Büyük data copy maliyetini azaltabilir. Buna karşılık synchronization ve race condition yönetimi gerekir. Shared memory kolayca global unbounded buffer'a dönüşmemelidir. Capacity ve ownership açık biçimde tanımlanmalıdır.
Transferable Objects
ArrayBuffer transfer edildiğinde ownership bir context'ten diğerine taşınabilir ve büyük kopyalama maliyeti önlenebilir. Transfer sonrası sender aynı buffer'ı normal şekilde kullanamaz. Bu davranış API contract içinde açık olmalıdır. Binary processing pipeline'larında oldukça faydalı olabilir. Small object'ler için transfer complexity gereksiz olabilir.
Worker Resource Limits
Worker creation sırasında V8'e ilişkin belirli resource limitleri tanımlanabilir. Bu limitler tüm process RSS için hard container sınırı değildir. Native veya shared memory ayrıca tüketilebilir. Worker limit aşımı task failure ve restart policy gerektirir. Production test worker OOM davranışını açıkça simüle etmelidir.
Worker Thread'ler Arasında Büyük Veri Nasıl Taşınmalı?
Worker'a büyük JavaScript object göndermek structured clone nedeniyle CPU ve memory maliyeti oluşturabilir. Aynı anda birçok task büyük payload kopyalarsa process RSS hızla büyür. Binary data için transferable ArrayBuffer daha verimli olabilir. SharedArrayBuffer ortak veri gerektiğinde kullanılabilir ancak synchronization maliyeti vardır. En iyi optimizasyon çoğu zaman worker'a gerçekten gerekli minimal datayı göndermektir.
Structured Clone
`postMessage` ile gönderilen birçok JavaScript value structured clone mekanizmasıyla kopyalanır. Büyük nested object'lerde serialization benzeri CPU ve allocation maliyeti oluşur. Sender ve receiver bir süre iki ayrı copy taşıyabilir. Worker task payload size limitlenmelidir. Benchmark copy time ve RSS artışını birlikte ölçmelidir.
Kopyalama Maliyeti
100 MB object'i dört worker'a kopyalamak teorik olarak yüzlerce megabyte ek memory oluşturabilir. Concurrent task sayısı arttığında footprint daha da büyür. CPU serialization maliyeti event loop latency'sini etkileyebilir. İş sadece küçük subset kullanıyorsa data önceden reduce edilmelidir. Büyük shared dataset için farklı architecture düşünülebilir.
Transferable ArrayBuffer
Transferable ArrayBuffer ownership'i worker'a taşıyarak data copy ihtiyacını azaltabilir. Sender buffer'ı transfer sonrasında kullanmamalıdır. Bu model image veya binary chunk processing için uygundur. Lifecycle ve ownership compile-time type tarafından tam korunmayabilir. Integration test transfer sonrası davranışı doğrulamalıdır.
SharedArrayBuffer
SharedArrayBuffer aynı memory'ye birden fazla worker erişimi sağlar. Copy overhead azalır fakat concurrent access synchronization gerektirir. Atomics kullanılacaksa correctness testleri önemlidir. Shared buffer maximum size ile sınırlandırılmalıdır. Business object graph yerine numeric veya binary shared state için daha doğal bir araçtır.
Büyük Objeleri Gereksiz Taşımamak
Worker yalnız image bytes kullanıyorsa tüm request object'i gönderilmemelidir. Minimal message schema memory ve coupling'i azaltır. Metadata primitive alanlara indirgenebilir. Worker result da yalnız gerekli output'u dönmelidir. Message size metric büyük payload regression'ını erken gösterir.
Node.js Memory Leak Nasıl Tespit Edilir?
Memory leak teşhisi gözleme dayalı ve tekrarlanabilir bir süreç olmalıdır. Önce production metrics leak pattern'ini gerçekten doğrular, ardından aynı davranış staging veya izole replica üzerinde yük altında tekrar üretilir. Baseline ve birkaç farklı noktada heap snapshot alınarak hangi object türlerinin kaldığı karşılaştırılır. Allocation profile büyümenin hangi code path'ten geldiğini gösterebilir. Fix uygulandıktan sonra aynı test yeniden çalıştırılmadan problem çözülmüş kabul edilmemelidir.
Production Metriklerini İncelemek
RSS, heapUsed, external, arrayBuffers, GC ve request rate aynı zaman aralığında açılmalıdır. Restart ve deployment event'leri grafiğe işaretlenmelidir. Memory yalnız trafik arttığında yükselip sonra düşüyor mu sorusu cevaplanır. Baseline uptime ile sürekli artıyorsa leak ihtimali güçlenir. Error ve queue metric'leri dependency incident etkisini açıklayabilir.
Leak Pattern'ini Doğrulamak
Tek spike leak değildir. Benzer workload ve GC döngülerinden sonra minimum memory değerlerinin sürekli yükselmesi aranır. Uptime ve memory arasında güçlü korelasyon olabilir. Listener count veya cache size gibi domain metric aynı trendi destekleyebilir. Pattern doğrulanmadan riskli production snapshot alınmamalıdır.
Reproducible Load Oluşturmak
Leak'i aynı endpoint veya job sequence ile tekrar üretmek root cause süresini ciddi azaltır. Request data cardinality production'a benzemelidir. Cache leak yalnız benzersiz key ile ortaya çıkıyorsa sabit test user'ı problemi gizleyebilir. Load rate production'ın makul bir ölçeğini temsil etmelidir. Test deterministic olduğunda fix karşılaştırması güvenilir olur.
Baseline Almak
Application warm-up tamamlandıktan sonra başlangıç memory değerleri kaydedilir. Heap snapshot alınacaksa ilk snapshot bu noktada olabilir. Active connection, listener ve cache size da not edilir. Baseline sürüm ve candidate sürüm aynı environment'ta test edilmelidir. OS page cache gibi dış etkiler mümkün olduğunca sabit tutulmalıdır.
Heap Snapshot
Snapshot V8 heap object graph'ının belirli andaki durumunu gösterir. Tek snapshot büyük object'leri gösterse de leak için comparison daha değerlidir. Constructor count ve retained size artışı incelenir. Retainers üzerinden object'i GC root'a bağlayan path bulunur. Production'da snapshot'ın blocking ve memory maliyeti nedeniyle kontrollü replica kullanılmalıdır.
Allocation Profile
Allocation profile hangi function ve call path'in memory allocation yaptığını gösterir. Leak object'inin nerede oluşturulduğunu bulmada snapshot'a tamamlayıcı olur. Sampling profiler daha düşük overhead ile uzun testte kullanılabilir. Allocation hotspot her zaman leak değildir, çünkü object kısa sürede GC olabilir. Retention ve allocation birlikte değerlendirilmelidir.
Root Cause
Root cause genellikle “çok object var” seviyesinden daha spesifik olmalıdır. Örneğin `sessionCache` Map entry'sinin TTL olmaması veya disconnect sonrası listener'ın silinmemesi net cause'dur. Fix owner ve lifecycle noktasını düzeltmelidir. Limit artırımı root cause değildir. Regression test aynı failure pattern'i otomatik yakalayacak biçimde eklenmelidir.
Fix Sonrası Tekrar Test
Aynı load generator, duration ve input distribution tekrar kullanılmalıdır. Memory baseline'ın plateau oluşturduğu doğrulanır. Throughput veya latency fix nedeniyle kötüleşmişse trade-off incelenir. Listener, cache ve connection count da tekrar kontrol edilir. Canary production rollout staging sonucunu gerçek traffic ile doğrular.
Sağlıklı Memory Grafiği Nasıl Görünür?
Sağlıklı Node.js heap grafiği çoğu zaman allocation arttıkça yükselen ve GC sonrasında düşen testere benzeri pattern gösterir. Bu şeklin kendisi zorunlu değildir çünkü runtime ve metric sampling davranışı farklılık gösterebilir. Önemli olan uzun zaman penceresinde GC sonrası baseline'ın makul bir aralıkta stabil kalmasıdır. Trafik spike sırasında geçici growth kabul edilebilir. Leak durumunda ise düşük noktalar bile zamanla yukarı taşınır.
Sawtooth Pattern
Object allocation heapUsed değerini yükseltir. Garbage collection kullanılmayan object'leri temizlediğinde grafik aşağı iner. Bu tekrar eden pattern normal olabilir. Minor ve major GC farklı büyüklükte düşüşler yaratabilir. Tek grafiğin şekline bakmak yerine GC events ile doğrulama yapılmalıdır.
GC Sonrası Düşüş
GC sonrası heapUsed anlamlı şekilde düşüyorsa kullanılmayan object'ler geri kazanılıyor demektir. Düşüş miktarı workload'a göre değişir. Cache warm-up sonrası baseline biraz yüksek kalabilir. Her cycle sonrasında minimum daha da yükseliyorsa retention araştırılmalıdır. Forced GC yalnız test karşılaştırmalarında kontrollü kullanılmalıdır.
Stable Baseline
Stable baseline uzun soak testte memory'nin belirli bant içinde kalmasıdır. Trafik aynıyken sürekli upward drift olmaması beklenir. Baseline deployment version ile karşılaştırılabilir. Yeni release sonrası yüzde 20 daha yüksek stable baseline leak değil fakat memory regression olabilir. Memory budget bu farkı kabul edip etmeyeceğini belirler.
Traffic ile Orantılı Geçici Growth
Concurrent request sayısı iki katına çıkınca pending object ve Buffer miktarı da artabilir. Trafik normale dönünce memory de bir süre sonra geri düşmelidir. Delay GC scheduling ve cache nedeniyle anlık olmayabilir. Request rate, active request ve memory aynı grafikte gösterilmelidir. Bu korelasyon normal capacity davranışını leak'ten ayırır.
Leak'te Sürekli Yükselen Baseline
Leak'te her workload döngüsü biraz daha fazla canlı state bırakır. GC spike'ları oluşsa da minimum heap değeri önceki seviyeye dönmez. Uzun uptime olan pod'lar yeni pod'lardan daha fazla memory kullanır. Bu pattern deployment restart'larıyla resetlenebilir ve fark edilmesi zorlaşabilir. Uptime normalize edilmiş dashboard faydalıdır.
process.memoryUsage() ile Memory Monitoring
`process.memoryUsage()` uygulama içinden temel memory metrics toplamak için yeterli başlangıç sağlar. Ancak her request'te çağrılmasına gerek yoktur. Periyodik sampling ve Prometheus gauge benzeri metric yaklaşımı daha uygundur. Değerler byte cinsinde tutulup dashboard'da MiB'a çevrilebilir. Pod ve instance label'ları controlled cardinality ile leak'in hangi replica'da başladığını bulmayı kolaylaştırır.
Periyodik Ölçüm
Memory metriği birkaç saniye veya onlarca saniye aralıkla sampling edilebilir. Çok sık çağrı özellikle büyük allocation map üzerinde ek overhead oluşturabilir. Sadece RSS için daha hızlı `process.memoryUsage.rss()` kullanılabilir. Sampling interval alert requirement ile uyumlu olmalıdır. Leak rate yavaşsa bir dakikalık interval bile yeterli olabilir.
MB Olarak Normalize Etmek
Runtime API byte döndürür. Metrics backend genellikle base unit olarak byte saklamayı tercih eder. Dashboard MiB veya GiB conversion yapabilir. Kod içinde 1000 ve 1024 tabanının karıştırılması confusion oluşturur. Metric ismi unit bilgisini açıkça taşımalıdır.
Prometheus Metric
RSS, heap used, heap total ve external gauge olarak export edilebilir. Standard process collector zaten bazı metrikleri sağlıyorsa duplicate metric üretilmemelidir. Custom heap space ölçümleri ayrıca eklenebilir. Label set küçük tutulmalıdır. Request ID veya user ID kesinlikle metric label olarak kullanılmamalıdır.
Pod / Instance Label
Pod name per replica troubleshooting için yararlıdır. Çok sık pod churn olsa bile operational dashboard'da gerekli olabilir. Long-term aggregate alert deployment veya service label üzerinden çalışabilir. Version label regression başlangıcını göstermeye yardımcı olur. Tenant gibi yüksek cardinality label eklenmemelidir.
Loglamak mı Metric Olarak Göndermek mi?
Sürekli memory trend için metric daha uygundur. Her 10 saniyede JSON memory logu yüksek log volume oluşturabilir. Incident snapshot veya diagnostic state loglanabilir. Metric aggregation ve alert işini daha verimli yapar. Log ise belirli event'e ilişkin contextual bilgi için kullanılmalıdır.
V8 Heap Statistics Nasıl Alınır?
`node:v8` modülü heap'in genel ve space bazlı istatistiklerini gözlemlemek için yerleşik API sunar. `v8.getHeapStatistics()` toplam heap limit ve kullanım bilgisi verir. `v8.getHeapSpaceStatistics()` ise V8 tarafından expose edilen space'leri ayrı görmeyi sağlar. Space listesi ve sırası V8 sürümüne göre değişebileceği için monitoring code belirli sabit indekslere güvenmemelidir. Bu veriler memory leak root cause değil ama heap pressure yönünü anlamak için yararlıdır.
v8.getHeapStatistics()
Bu API heap size limit ve çeşitli heap kullanım alanlarını içeren object döndürür. Startup sırasında actual heap limit gözlemlenebilir. Deployment flag'inin gerçekten uygulandığı doğrulanabilir. Metric sampling çok sık yapılmamalıdır. Version upgrade sonrası field semantics resmi dokümantasyondan kontrol edilmelidir.
v8.getHeapSpaceStatistics()
API heap'i oluşturan space'ler hakkında size ve used değerleri sunar. Old space büyümesi leak araştırmasında faydalı sinyal olabilir. Space isimleri V8 implementation detail'e bağlı olarak zaman içinde değişebilir. Monitoring bilinmeyen space isimlerini güvenli şekilde desteklemelidir. Alert doğrudan tek space adına aşırı bağımlı olmamalıdır.
Heap Size Limit
`heap_size_limit` mevcut V8 heap limitini byte cinsinden anlamayı sağlar. Config'te set edilen flag ile runtime sonucu karşılaştırılabilir. Container limit ile aradaki fark headroom hesabına girdi olur. Worker thread'lerde isolate-specific limits ayrıca incelenebilir. Limit metric startup sonrası sabit olduğu için sık sampling gerektirmez.
Old Space Kullanımı
Old space uzun ömürlü object'lerin önemli bölümünü barındırır. Buradaki sürekli growth cache veya retained request state gibi problemlere işaret edebilir. Major GC sonrası used size trendi özellikle yararlıdır. Tek spike leak değildir. Snapshot comparison hangi object'lerin bu growth'a katkı verdiğini gösterir.
Space Bazında Growth
Space metrics hangi generation'da pressure oluştuğunu anlamaya yardımcı olur. Young generation yüksek churn gösterirken old generation stable kalabilir. Bu allocation-heavy fakat leak olmayan workload'a işaret edebilir. Old space baseline yükseliyorsa retention araştırılır. Version değişikliğinde space architecture değişebileceği için dashboard yorumları yeniden doğrulanmalıdır.
Heap Snapshot Nedir?
Heap snapshot V8 heap üzerindeki object graph'ının belirli bir andaki fotoğrafıdır. Constructor, reference ilişkileri, shallow size ve retained size gibi bilgiler üzerinden hangi object'lerin belleği tuttuğu incelenebilir. Snapshot özellikle karşılaştırmalı leak analizinde değerlidir. Ancak üretimi event loop'u bloklayabilir ve önemli ek memory gerektirebilir. Bu nedenle production'da sıradan monitoring aracı değil kontrollü incident artifact'ı olarak kullanılmalıdır.
Object Graph
Snapshot nesneleri ve aralarındaki reference edge'lerini graph olarak temsil eder. Leak teşhisi yalnız object count değil bu graph ilişkisini inceler. Global Map yüz binlerce entry'yi tek root altında tutabilir. Graph üzerinden dominator ve retaining path görülebilir. Büyük graph dosyası hassas application verisi de içerebilir.
Constructor
DevTools summary object'leri constructor adına göre gruplayabilir. Belirli custom class sayısının snapshot'lar arasında sürekli artması güçlü ipucudur. Plain Object veya Array gibi generic constructor'lar daha fazla investigation gerektirir. Constructor count tek başına root cause değildir. Retainers view object'lerin neden yaşadığını gösterir.
Shallow Size
Shallow size object'in doğrudan kendi memory maliyetini gösterir. Küçük cache node veya closure önemsiz görünebilir. Ancak büyük graph'ı retained tutuyorsa shallow size yanıltıcı olur. Summary sıralamasında yalnız bu column'a bakılmamalıdır. Retained size ile birlikte değerlendirilmelidir.
Retained Size
Retained size object silindiğinde onunla birlikte erişilemez olacak tahmini total graph boyutudur. Dominator object'leri bulmak için oldukça yararlıdır. Büyük retained size application root için normal olabilir. Comparison snapshot'ta artan retained size daha anlamlı sinyal verir. Leak fix hangi root reference'ın kesileceğini bu analizle belirleyebilir.
GC Root
GC root object graph'ın collection açısından başlangıç noktalarıdır. Root'a reference zinciri bulunan object canlı kabul edilir. Leak object'inin root'a kadar yolu bulunmalıdır. Global collection, listener registry veya active timer sık görülen zincirlerdir. Root type uygulamanın cleanup noktasını anlamaya yardımcı olur.
Retainer
Retainer bir object'e reference tutan başka object veya runtime yapısıdır. Bir object'in birden fazla retainer'ı olabilir. Bir reference'ı silmek yetmeyebilir çünkü başka path üzerinden hâlâ reachable kalabilir. Retainers görünümü bütün yolları incelemeyi sağlar. Fix sonrası snapshot'ta aynı path'in kaybolduğu doğrulanmalıdır.
Node.js Heap Snapshot Nasıl Alınır?
Node.js heap snapshot Chrome Inspector, `v8.writeHeapSnapshot()`, `v8.getHeapSnapshot()` veya uygun runtime signal seçenekleriyle alınabilir. Her yöntem production'da aynı risk profilini taşır çünkü snapshot üretimi V8 heap'i senkron şekilde analiz eder. Güncel Node.js belgeleri snapshot üretiminin heap boyutunun yaklaşık iki katına varan ek memory gerektirebileceğini ve event loop'u bloklayabileceğini belirtir. Worker thread snapshot'ı yalnız ilgili isolate'ı temsil eder. Bu nedenle hangi process veya worker'dan dump alındığı incident kaydında açıkça belirtilmelidir.
Chrome Inspector
Inspector üzerinden Chrome DevTools Memory paneliyle snapshot alınabilir. Local veya kontrollü staging environment için kullanımı kolaydır. Production inspector port'unu public network'e açmak ciddi security riskidir. Tunnel veya internal access gerekiyorsa güçlü erişim kontrolü uygulanmalıdır. Incident sonrasında inspector kapatılmalıdır.
v8.writeHeapSnapshot()
`v8.writeHeapSnapshot()` mevcut isolate heap'ini `.heapsnapshot` dosyasına yazar. Function synchronous snapshot generation nedeniyle request processing'i durdurabilir. Büyük heap'te süre uzayabilir. File path güvenli ve yeterli disk alanına sahip olmalıdır. Snapshot tamamlandıktan sonra artifact erişimi sınırlandırılmalıdır.
v8.getHeapSnapshot()
`v8.getHeapSnapshot()` snapshot JSON'unu Readable stream olarak verir. Snapshot generation'ın kendisi yine senkron ve memory-intensive olabilir. Stream elde edilmesi underlying collection maliyetini ortadan kaldırmaz. Output secure storage'a yazılabilir. Snapshot schema V8'e özgü olduğu için custom parser'a kalıcı dependency oluşturmak risklidir.
Signal ile Snapshot
Node.js uygun CLI configuration ile signal geldiğinde heap snapshot üretmeyi destekleyebilir. Bu yöntem shell erişimi olan incident runbook için faydalıdır. Signal production service'in başka amacıyla çakışmamalıdır. Snapshot anında pod trafikten çıkarılmalıdır. Signal trigger yalnız authorized operations ekibi tarafından kullanılmalıdır.
Near-Heap-Limit Snapshot
`--heapsnapshot-near-heap-limit` heap limiti yaklaşırken otomatik snapshot yazmayı sağlar. Güncel Node.js sürümlerinde bu flag production investigation için daha olgun bir API hâline gelmiştir. Yine de snapshot ek memory ve CPU ister. Zaten limit yakınındaki process üzerinde bu overhead OOM riskini artırabilir. Controlled canary veya staging reproduction çoğu durumda daha güvenlidir.
Heap Snapshot Production'da Neden Risklidir?
Heap snapshot production process üzerinde ağır bir diagnostic operasyondur. Node.js belgeleri snapshot oluşturmanın event loop'u heap büyüklüğüne bağlı süre boyunca blokladığını ve yaklaşık iki kat heap memory gerektirebildiğini belirtir. Zaten memory pressure altındaki process bu ek kullanım nedeniyle OOM yaşayabilir. Kullanıcı trafiği snapshot süresince timeout olabilir. Bu yüzden leak gösteren replica önce load balancer'dan drain edilmeli ve yeterli memory headroom doğrulanmalıdır.
Event Loop'un Bloke Olması
Snapshot generation synchronous çalışır. Bu sırada JavaScript handler'lar ilerleyemez. Büyük heap birkaç saniye veya daha uzun süre request timeout yaratabilir. Health probe failure pod'un snapshot sırasında restart edilmesine bile yol açabilir. Replica traffic'ten çıkarılarak bu risk azaltılmalıdır.
Geçici Memory Kullanımının Artması
Snapshot object graph'ını serialize etmek ek memory gerektirir. Node.js documentation bu ihtiyacın heap büyüklüğünün yaklaşık iki katı seviyesine çıkabileceği konusunda uyarır. Container headroom yetersizse kernel process'i öldürebilir. Snapshot öncesi current RSS ve limit kontrol edilmelidir. Ek replica açmak operasyon riskini azaltabilir.
OOM Riski
Leak zaten process'i limit yakınına getirmiş olabilir. Snapshot bu durumda son allocation'ı tetikleyebilir. Artifact tamamlanmadan process ölürse hem trafik hem diagnostic fırsat kaybedilir. Önce traffic drain ve gerekiyorsa memory limitli izole reproduction tercih edilmelidir. Near-limit snapshot flag'i kullanılıyorsa risk bilinçli kabul edilmelidir.
Büyük Heap'te Uzun Snapshot Süresi
Heap büyüklüğü arttıkça object graph traversal ve serialization süresi artabilir. Çok büyük heap için operation dakikalarca request işleyemeyen bir process yaratabilir. Timeout veya orchestrator health checks bunu process failure olarak yorumlayabilir. Dedicated replica daha güvenli bir seçenektir. Snapshot duration incident kaydına eklenerek future runbook geliştirilir.
Production Replica Üzerindeki Trafiği Drain Etmek
Readiness false yapılarak yeni traffic durdurulabilir. Existing request'lerin tamamlanması için kısa süre verilir. Snapshot yalnız replica gerçekten izole olduktan sonra alınır. Sonrasında process restart edilmesi güvenli olabilir. Bu prosedür runbook içinde adım adım test edilmelidir.
Heap Snapshot Güvenliği
Heap snapshot yalnız teknik diagnostic dosya değildir, process memory içinde bulunan hassas verileri de içerebilir. Token, password, session object, request body veya kişisel veriler snapshot'a yansıyabilir. Dosya production database dump kadar hassas kabul edilmelidir. Encryption, sınırlı erişim ve retention policy uygulanmalıdır. Incident tamamlandıktan sonra secure deletion prosedürü işletilmelidir.
Memory İçinde Token Bulunması
Access token veya API credential process memory'de string olarak bulunabilir. Snapshot object graph içinde bu value görülebilir. Artifact broad team drive'a yüklenmemelidir. Access yalnız incident için yetkili kişilere verilmelidir. Token exposure ihtimali varsa security ekibi credential rotation gereksinimini değerlendirmelidir.
Password
Login request processing sırasında plaintext password kısa süre memory'de bulunabilir. Snapshot tam o anda alınırsa bu data artifact'a girebilir. Password request body'sini global log veya cache'e yazmamak exposure süresini azaltır. Snapshot hassas secret içeriyor varsayımıyla korunmalıdır. Public issue'ya heap snapshot eklemek kesinlikle uygun değildir.
PII
User adı, email, adres veya başka kişisel veriler object graph içinde bulunabilir. Data protection policy diagnostic artifact'ları da kapsamalıdır. Anonymization snapshot sonrasında kolay olmayabilir. Production yerine staging reproduction bu riski ciddi azaltır. Gerçek production dump zorunluysa access ve retention kaydı tutulmalıdır.
Request Body
Active request body object'leri snapshot'ta görülebilir. Büyük body leak'in kendisi de olabilir. Payload hassas ise diagnostic file daha yüksek güvenlik seviyesine alınmalıdır. Snapshot paylaşımı yalnız secure internal channel üzerinden yapılmalıdır. Root cause raporu raw data yerine anonymized object type bilgisi kullanmalıdır.
Session
Session store process-local ise kullanıcı session data'sı heap snapshot içinde yer alabilir. Session token veya identity bilgi leakage riski taşır. Snapshot'ın external vendor ile paylaşılması gerekiyorsa legal ve security review gerekebilir. Minimal reproduction çoğu durumda daha güvenlidir. Session data'nın kendisinin bounded ve minimal tutulması ayrı memory avantajı sağlar.
Snapshot Encryption
Artifact storage at rest encryption kullanmalıdır. Transfer sırasında güvenli protocol gereklidir. Encryption key snapshot ile aynı storage üzerinde açık biçimde tutulmamalıdır. Temporary local disk file incident sonunda silinmelidir. Backup policy diagnostic dump'ları gereksiz uzun süre saklamamalıdır.
Sınırlı Erişim
Heap dump erişimi role-based kontrol altında olmalıdır. Her developer'ın production snapshot download yetkisine ihtiyacı yoktur. Access log audit için saklanabilir. Incident ticket artifact location ve owner bilgisini içerebilir. Erişim incident kapandıktan sonra kaldırılmalıdır.
Retention ve Secure Deletion
Snapshot yalnız root cause analizi için gerekli süre kadar tutulmalıdır. Default sınırsız retention privacy ve security riskini artırır. Incident kapandığında artifact güvenli şekilde silinmelidir. Object storage lifecycle rule bu işlemi otomatikleştirebilir. Root cause raporu raw snapshot'a ihtiyaç duymayacak yeterli teknik bulgu içermelidir.
Three-Snapshot Technique
Three-snapshot technique leak'i tek dump yerine zaman içinde karşılaştırmalı analiz etmeyi amaçlar. Application önce warm-up edilir ve ilk snapshot alınır. Daha sonra aynı leak tetikleyici workload çalıştırılarak ikinci ve üçüncü snapshot oluşturulur. Her aşamada mümkünse GC sonrası karşılaştırılabilir koşullar sağlanır. Snapshot'larda sürekli büyüyen constructor, retained size ve retaining path leak kaynağına yaklaşmayı sağlar.
Warm-Up
Startup sonrası module ve normal cache yüklemelerinin tamamlanması beklenir. Aksi hâlde normal initialization growth leak sanılabilir. Fixed number request ile application stabil hâle getirilebilir. Memory baseline kaydedilir. Her test run aynı warm-up procedure kullanmalıdır.
Snapshot 1
İlk snapshot warmed baseline'ı temsil eder. Bu noktada test target endpoint henüz yoğun yük altında çalıştırılmamış olabilir. Constructor count ve heap size kayıt altına alınır. Snapshot file güvenli isimle saklanır. Production'da operation riskliyse staging replica tercih edilir.
Load
Leak trigger olduğu düşünülen request veya job set'i belirli sayıda çalıştırılır. Input cardinality production'a benzemelidir. Cache leak testinde unique key kullanılması gerekebilir. Trafik tamamlandıktan sonra kısa stabilize süresi verilebilir. Request count ve errors kaydedilir.
Snapshot 2
İkinci snapshot ilk load sonrasındaki retained state'i gösterir. Comparison view Snapshot 1 ile farkı ortaya çıkarır. Büyük artış gösteren constructor'lar listelenir. Normal cache warm-up candidate listeden ayrılır. Retainers path root'a kadar takip edilir.
Daha Fazla Load
Aynı workload tekrar çalıştırılır. Leak varsa aynı object türü benzer hızla artmaya devam edebilir. Normal bounded cache limitine ulaşmışsa artık büyümemelidir. Memory growth rate hesaplanabilir. Listener ve collection count gibi application metric'leri de kaydedilir.
Snapshot 3
Üçüncü snapshot growth trend'in tesadüf olmadığını doğrulamaya yardımcı olur. Snapshot 1, 2 ve 3 arasında düzenli artış gösteren object'ler öncelik kazanır. Retained size artışı absolute object count'tan daha anlamlı olabilir. GC root path aynı kalıyorsa leak source daha netleşir. Fix hedefi bu owner reference olur.
Comparison
DevTools Comparison görünümü constructor count ve size farklarını gösterir. Her artış bug değildir çünkü cache veya application state bilinçli büyüyebilir. Business lifecycle ile teknik growth karşılaştırılır. Sınırsız büyümesi gerekmeyen object family önceliklendirilir. Comparison sonucu source code call path ile eşleştirilir.
Retaining Path
Final teşhis object'in neden hayatta kaldığını açıklamalıdır. Global Map, listener veya pending Promise gibi root bağlantısı bulunur. Bu reference cleanup edildiğinde object graph'ın geri kazanılması beklenir. Fix sonrası aynı three-snapshot procedure tekrarlanır. Growth ortadan kalktıysa regression test otomatikleştirilebilir.
Chrome DevTools Memory Panel Nasıl Kullanılır?
Chrome DevTools Memory panel Node.js heap snapshot ve allocation profile dosyalarını analiz etmek için güçlü bir arayüz sunar. Summary constructor bazlı görünüm sağlar, Comparison iki snapshot arasındaki farkı gösterir ve Retainers object'in neden hayatta kaldığını anlamaya yardım eder. Allocation sampling hangi code path'in çok memory oluşturduğunu gösterir. Tek bir görünüm üzerinden karar vermek yerine bu araçlar birlikte kullanılmalıdır. Production snapshot'ı açarken workstation güvenliği ve artifact sensitivity unutulmamalıdır.
Summary
Summary snapshot içindeki object'leri constructor bazında gruplar. Count, shallow size ve retained size gibi alanlar ilk taramayı kolaylaştırır. En büyük object her zaman leak root'u değildir. Custom class isimleri application-level object family'lerini hızlı buldurabilir. Generic Array ve Object için retainer analizi gerekebilir.
Comparison
Comparison iki snapshot arasında object count ve size değişimini gösterir. Leak investigation için tek snapshot'tan daha değerlidir. Üç farklı noktayı ikili karşılaştırmalarla incelemek growth consistency sağlar. Negative delta GC tarafından temizlenen object'leri gösterebilir. Sürekli positive retained growth candidate list oluşturur.
Containment
Containment object graph'ın hangi container altında bulunduğunu görmeye yardımcı olur. Büyük collection içinde retained entry'ler keşfedilebilir. Tree geniş olduğu için filtering gerekebilir. Application module veya custom class üzerinden ilerlemek daha hızlıdır. Containment görünümü ownership structure hakkında fikir verir.
Retainers
Retainers seçili object'i hangi diğer object'lerin tuttuğunu gösterir. Path GC root'a kadar takip edilir. Closure, listener ve Map leak'leri burada belirginleşebilir. Aynı object birden fazla path tarafından tutuluyorsa bütün gerekli reference'lar incelenmelidir. Fix source code ile bu path arasında net bağlantı kurmalıdır.
Allocation Sampling
Allocation sampling düşük overhead ile hangi call stack'lerin memory allocation yaptığını tahmini olarak gösterir. Uzun staging load testlerinde faydalıdır. Büyük allocator function leak olmayabilir çünkü object'ler kısa ömürlü olabilir. Snapshot retention bilgisiyle birlikte kullanıldığında daha güçlü sonuç verir. Sampling interval ve profile duration workload'a göre seçilmelidir.
Allocation Timeline
Allocation timeline object'lerin zaman içinde allocation ve survival davranışını incelemek için kullanılabilir. Belirli user action sonrası kalan object'leri görmek mümkündür. Uzun testte profile dosyası büyüyebilir. Staging veya local reproduction için daha uygundur. Production traffic üzerinde overhead dikkatle değerlendirilmelidir.
Shallow Size ve Retained Size Arasındaki Fark
Heap analysis sırasında shallow size ve retained size birbirinden farklı sorulara cevap verir. Shallow size object'in kendi doğrudan memory maliyetidir. Retained size ise object ortadan kalktığında onunla birlikte erişilemez olacak graph miktarını gösterir. Leak root'u çoğu zaman küçük shallow fakat büyük retained size'a sahiptir. Bu yüzden summary ekranında yalnız en büyük object'leri aramak yanlış teşhise yol açabilir.
Küçük Closure'ın Büyük Objeleri Tutması
Closure function'ın kendisi birkaç byte veya küçük metadata kullanabilir. Ancak lexical context üzerinden yüzlerce megabyte array'e reference tutabilir. Shallow size bu problemi göstermez. Retained size ve Retainers paneli gerçek impact'i ortaya çıkarır. Closure scope daraltıldığında bütün graph GC için uygun hâle gelebilir.
Retaining Tree
Retaining tree object'i root'a bağlayan parent chain'leri gösterir. Leak source genellikle bu tree üzerinde tekrar eden owner pattern'dir. Request object shared singleton'a bağlıysa architecture bug daha görünür hâle gelir. Tree branch'lerinin tamamı gerekli olmayabilir. En kısa veya anlamlı strong reference path source code ile eşleştirilmelidir.
Dominator
Dominator object graph'ın büyük bölümünün yaşamını kontrol eden node olarak düşünülebilir. Bir dominator kaldırıldığında çok sayıda child object de erişilemez olabilir. Cache container tipik dominator örneğidir. DevTools retained size bu tür object'leri önceliklendirmeyi kolaylaştırır. Dominator'ın büyük olması her zaman bug değildir çünkü application root normal olarak büyük olabilir.
Büyük Retained Graph
Büyük retained graph tek bir owner'ın altında çok sayıda object bulunduğunu gösterir. Business requirement bu graph'ın gerçekten process lifetime boyunca yaşamasını gerektiriyor mu sorulmalıdır. Eğer yalnız request lifetime verisiyse leak ihtimali yüksektir. Cache ise maximum size requirement kontrol edilir. Fix graph'ın tamamını kopyalamak yerine owner lifecycle'ını düzeltmelidir.
--heap-prof Nedir?
`--heap-prof` Node.js'in sampling heap profiler desteğini process başlangıcından itibaren etkinleştirebilen CLI seçeneğidir. Güncel desteklenen Node.js hatlarında heap profile flag'leri stable durumdadır. Profile allocation hotspot'larını görmek için kullanılabilir. Heap snapshot'tan farklı olarak belirli andaki full object graph yerine allocation sampling odağı taşır. CI veya staging memory regression analizinde kontrollü kullanımı faydalıdır.
Sampling Heap Profiler
Sampling profiler bütün allocation'ları eksiksiz kaydetmek yerine örnekleme yaklaşımı kullanır. Bu durum overhead'i full tracing'e göre azaltabilir. Sonuç hangi function'ların daha fazla memory allocation yaptığını gösterir. Sampling değeri mutlak byte accounting olarak yorumlanmamalıdır. Hotspot optimizasyonu sonrası profile tekrar alınmalıdır.
Heap Profile Dosyası
Process sonunda veya belirli profiler akışında heap profile dosyası üretilebilir. Artifact DevTools gibi destekleyen araçlarla analiz edilebilir. Dosya source path ve uygulama yapısı hakkında hassas bilgi taşıyabilir. Secure artifact storage kullanılmalıdır. CI artifact retention gereksiz uzun tutulmamalıdır.
Allocation Hotspot
Hotspot çok sayıda veya büyük memory allocation yapan call path'tir. Bu code memory leak olmak zorunda değildir. Eğer object'ler hemen GC oluyorsa sorun daha çok GC pressure ve CPU olabilir. Snapshot retained object'lerle cross-check yapılmalıdır. Gereksiz array copy veya serialization hotspot'ları performans optimizasyonu için iyi adaydır.
Heap Snapshot ile Farkı
Snapshot belirli andaki live object graph'ını ayrıntılı gösterir. Heap profile allocation'ın nerede gerçekleştiğine odaklanır. Leak teşhisinde snapshot “neden hâlâ yaşıyor?”, profiler ise “nerede oluşturuluyor?” sorusuna cevap verir. İkisi birlikte daha güçlüdür. Production risk profilleri de farklı olduğu için araç seçimi incident koşuluna göre yapılmalıdır.
CI/Staging Kullanımı
Memory regression load test sırasında `--heap-prof` ile allocation behavior version bazında karşılaştırılabilir. Production traffic'e profiler eklemeden önce overhead staging'de ölçülmelidir. Profile size ve artifact security hesaba katılmalıdır. Candidate release'de yeni hotspot ortaya çıkarsa pipeline review tetikleyebilir. Her build için profile saklamak yerine yalnız regression veya scheduled testlerde çalıştırmak daha ekonomik olabilir.
--heapsnapshot-near-heap-limit Nedir?
`--heapsnapshot-near-heap-limit` V8 heap kullanımı limite yaklaşırken otomatik heap snapshot üretmeye çalışır. Birden fazla snapshot sayısı belirtilerek OOM öncesi growth comparison için veri elde edilebilir. Güncel Node.js belgeleri snapshot üretiminin memory ve zaman maliyeti olduğunu ayrıca vurgular. Zaten memory pressure altındaki process için bu flag ek risk taşır. Production kullanımında dedicated replica ve yeterli container headroom tercih edilmelidir.
Heap Limit Yaklaşırken Otomatik Snapshot
Flag manuel incident müdahalesi olmadan snapshot alınmasını sağlayabilir. Leak hızlı ilerliyorsa insan müdahalesinden önce artifact elde etmek faydalıdır. Snapshot generation GC tetikleyebilir ve heap kullanımını geçici olarak azaltabilir. Her trigger kesin artifact garantisi vermeyebilir. Disk kapasitesi ve file permission önceden test edilmelidir.
Birden Fazla Snapshot
Maximum snapshot count verilerek limit yaklaşımında birkaç dump üretilebilir. Bu dump'lar object growth comparison için kullanılabilir. Her snapshot ek resource tüketir. Çok yüksek count production stability'yi daha da bozabilir. İki veya üç kontrollü snapshot çoğu leak investigation için yeterli olabilir.
OOM Investigation
OOM öncesi snapshot normal monitoring'de yakalanmayan retaining graph'ı gösterebilir. Process öldükten sonra heap state kaybolacağı için artifact değerlidir. Incident timeline snapshot timestamp'leriyle eşleştirilmelidir. Container restart logları dump dosyasının kalıcı volume'da olup olmadığını etkiler. Ephemeral filesystem kullanılıyorsa artifact collection planı gerekir.
Ek Memory Overhead
Snapshot generation ciddi geçici memory ister. Limit yakınında bu durum kernel OOM riskini artırır. Flag'in sağladığı diagnostic fayda ile availability riski dengelenmelidir. Staging reproduction mümkünse daha güvenli yaklaşım olabilir. Production'da yalnız selected canary üzerinde etkinleştirmek blast radius'u azaltır.
Production Kullanım Riski
Automatic snapshot event loop'u bloke edebilir ve disk I/O oluşturur. User traffic alan replica timeout üretmeye başlayabilir. Readiness otomatik düşmediği için load balancer trafik göndermeye devam edebilir. Feature flag ile yalnız investigation döneminde açılması uygundur. Incident bittiğinde configuration kaldırılmalıdır.
GC Logları Nasıl Analiz Edilir?
GC logları V8 collector'ın ne zaman, hangi tür collection yaptığı ve heap'i ne kadar küçülttüğü hakkında ayrıntı verir. `--trace-gc` gibi V8 tracing seçenekleri staging veya kontrollü diagnostic ortamda kullanılabilir. Frequent major GC, uzun pause ve collection sonrası çok az memory kazanımı heap pressure sinyalidir. Log hacmi production'da yüksek olabilir. GC log analizi heap snapshot ve latency metric'leriyle birlikte yapılmalıdır.
--trace-gc
Flag V8 garbage collection event'lerini stderr üzerinde ayrıntılı biçimde gösterebilir. Minor ve major collection türleri, süre ve heap değerleri görülebilir. High traffic production'da log volume oluşturabilir. Staging soak test veya izole replica daha güvenli kullanım alanıdır. Output format V8 sürümüyle değişebileceği için parser'a aşırı bağımlı otomasyon dikkatle yazılmalıdır.
Minor GC
Sık minor GC yüksek young generation allocation rate'i gösterebilir. Tek başına leak değildir çünkü kısa ömürlü object churn normal olabilir. Pause süreleri düşükse impact sınırlı kalabilir. CPU utilization yükseliyorsa allocation hotspot araştırılır. JSON mapping veya temporary array creation sık nedenlerdir.
Major GC
Frequent major GC old generation pressure'a işaret edebilir. Collection sonrası heap çok az düşüyorsa live object set büyüktür. Cache bloat veya leak ihtimali değerlendirilir. Heap limit fazla küçükse de major GC sıklaşabilir. Snapshot ve memory budget iki ihtimali ayırır.
Pause Duration
GC pause duration tail latency üzerinde doğrudan etki oluşturabilir. P99 request spike ile aynı timestamp'te gerçekleşen GC event'i güçlü korelasyon sağlar. Tek uzun pause yerine distribution izlenmelidir. Runtime upgrade GC behavior'ını değiştirebilir. Benchmark aynı workload ile version karşılaştırması yapmalıdır.
Heap Before/After
GC logu collection öncesi ve sonrası heap değerlerini gösterebilir. Büyük düşüş çok sayıda reclaimable object olduğunu gösterir. Küçük düşüş live set'in yüksek olduğunu düşündürür. Zaman içinde after değeri sürekli yükseliyorsa leak pattern oluşabilir. Bu değer application traffic ile normalize edilmelidir.
Frequent Major GC
Major GC'nin kısa aralıklarla tekrar etmesi CPU ve latency için kötü işarettir. Heap limit yaklaşımı, büyük cache veya memory leak neden olabilir. Sadece heap limit artırmak önce sebep bilinmeden yapılmamalıdır. Snapshot live set composition'ı gösterir. Fix sonrası GC frequency ve latency tekrar ölçülmelidir.
Clinic.js ile Memory Profiling
Clinic.js Node.js performance investigation için farklı profiling araçlarını bir araya getiren açık kaynak bir araç setidir. Memory probleminde heap profiler yaklaşımı allocation davranışını incelemeye yardımcı olabilir. Doctor daha genel event loop ve runtime sorunlarını, Flame ise CPU call stack'lerini anlamak için kullanılabilir. Tooling production traffic üzerinde doğrudan açılmadan önce staging overhead testi yapılmalıdır. En değerli kullanım gerçek production benzeri load altında reproducible problem oluşturmaktır.
Clinic Doctor
Doctor application'ın CPU, event loop ve başka runtime davranışlarını genel olarak incelemeye yardımcı olur. Memory incident yalnız heap değil event loop stall ile birlikteyse başlangıç resmi sağlar. Tool çıktısı root cause proof değil investigation input'u kabul edilmelidir. Profiling workload sabit ve tekrarlanabilir olmalıdır. Artifact hassas source veya runtime bilgisi taşıyabileceği için kontrollü saklanmalıdır.
Heap Profiler
Heap profiler allocation ve memory davranışını call path ile ilişkilendirmeye yardımcı olur. Leak snapshot ile tespit edildikten sonra hangi kodun object oluşturduğunu bulmak kolaylaşabilir. Sampling overhead production benzeri testte ölçülmelidir. Çok kısa test yavaş leak'i yakalamayabilir. Soak senaryosu gerektiğinde profile window uzatılabilir.
Flame
Flame graph ağırlıklı olarak CPU profiling için kullanılır. GC pressure yüksekse allocation veya serialization yapan hot function'lar CPU profilinde görünür olabilir. Bu doğrudan memory ownership kanıtı değildir. Heap profiler ve snapshot ile birlikte yorumlanmalıdır. Memory incident'ın aslında CPU-bound parser problemi olduğu durumlar bu karşılaştırmada ortaya çıkabilir.
Production Benzeri Load
Profiler boş local request üzerinde çalıştırıldığında gerçek bottleneck görünmeyebilir. Payload size, concurrency ve key cardinality production'a benzemelidir. Cache leak için unique key dağılımı önemlidir. WebSocket test connection churn içermelidir. Profiling sonucu workload tanımıyla birlikte raporlanmalıdır.
Staging Kullanımı
Staging profiler overhead'i ve sensitive data riskini azaltır. Ancak staging data production problemine benzemiyorsa leak reproduce olmayabilir. Sanitized production-like dataset hazırlanabilir. Resource limitler production container ile aynı tutulmalıdır. Fix doğrulaması canary production aşamasıyla tamamlanmalıdır.
0x ve Flame Graph Kullanımı
0x gibi flame graph araçları öncelikle CPU call stack'lerini analiz etmek için kullanılır. Memory leak'in kendisini doğrudan heap snapshot kadar net göstermez. Buna rağmen yüksek allocation rate veya serialization nedeniyle GC pressure oluşturan hot function'ları bulmada yardımcı olabilir. CPU ve memory problemini birbirinden ayırmak önemlidir. Profiling tool production üzerinde kullanılacaksa overhead ve artifact security önce staging'de ölçülmelidir.
CPU vs Memory Problemi
Yüksek RSS ile yüksek CPU aynı anda görülebilir fakat aynı root cause'a sahip olmayabilir. Frequent GC memory pressure nedeniyle CPU yükseltebilir. Heavy compression ise CPU yükseltirken memory normal olabilir. Flame graph hangi function'ların CPU zamanı tükettiğini gösterir. Heap metrics root cause'un memory tarafını tamamlar.
Allocation Path
CPU flame graph doğrudan allocation graph değildir. Yine de object üretimi yoğun parser veya mapping function'ları hot path olarak görülebilir. Heap profiler daha doğrudan allocation bilgisi verir. İki araç arasında aynı call site görülüyorsa optimization adayı güçlenir. Fix sonrası CPU ve allocation miktarı birlikte karşılaştırılmalıdır.
Hot Functions
Hot function CPU zamanının önemli bölümünü tüketen function'dır. `JSON.stringify`, mapper veya compression code sık örnek olabilir. Function aynı zamanda büyük temporary object oluşturuyorsa GC pressure artabilir. Source optimization object copy sayısını azaltabilir. Ancak readability ve correctness pahasına micro optimization yapılmamalıdır.
GC Pressure'a Sebep Olan Allocation'lar
Her request'te dev intermediate array oluşturmak minor ve major GC sıklığını artırabilir. Leak olmasa bile allocation churn latency'yi etkiler. Heap profiler allocation source'u, GC logs collection frequency'yi gösterir. Flame graph CPU cost'u tamamlar. Bu üç veri aynı code path'i işaret ediyorsa optimization etkisi daha güvenilir olur.
Node.js Diagnostic Reports
Node.js diagnostic report process'in runtime durumunu JSON dosyası olarak yakalamaya yarayan yerleşik teşhis özelliğidir. Report JavaScript ve native stack, heap bilgisi, platform bilgisi ve resource usage gibi alanlar içerir. Uncaught exception, fatal error veya signal ile üretilecek şekilde yapılandırılabilir. Heap snapshot'a göre farklı ve genellikle daha hafif bir diagnostic artifact sağlar. Incident runbook'ta snapshot almadan önce diagnostic report toplamak sıkça daha düşük riskli bir adımdır.
Process Durumu
Report process ID, Node.js version ve runtime event bilgisi sağlar. Incident'ın hangi binary ve deployment üzerinde gerçekleştiği doğrulanabilir. Command line flags heap setting'i anlamaya yardımcı olabilir. Environment bilgisi hassas değer taşıyabileceği için modern Node seçenekleriyle gerektiğinde excluded edilmelidir. Artifact yine güvenli saklanmalıdır.
JavaScript Stack
Diagnostic report JavaScript stack trace bilgisi içerebilir. Fatal veya exception bağlamında hangi execution path'in aktif olduğu görülebilir. Memory leak doğrudan stack'ten bulunmayabilir. Ancak OOM öncesi aktif operation konusunda ipucu sağlar. Source map policy stack readability'yi etkileyebilir.
Native Stack
Native stack Node runtime veya addon tarafındaki crash investigation için yardımcı olabilir. JavaScript heap snapshot'ın görmediği native problemde önemli context sunar. Symbol availability stack'in okunabilirliğini etkiler. Native addon version bilgisi deployment manifest ile eşleştirilmelidir. Root cause gerekiyorsa native profiler ile devam edilir.
Resource Usage
Report CPU, memory ve çeşitli process resource bilgileri içerebilir. Incident timestamp'teki state merkezi metric ile karşılaştırılır. Open handle bilgisi connection veya timer sorununa ipucu verebilir. Tek report trend sağlamaz. Bu nedenle time series monitoring'in yerine değil tamamlayıcısıdır.
Heap Bilgisi
Diagnostic report V8 heap statistics içerir ancak full object graph snapshot değildir. Heap limit ve used değerleri OOM türünü anlamaya yardımcı olur. Büyük retained class'ı doğrudan göstermez. Daha düşük diagnostic risk nedeniyle ilk aşamada tercih edilebilir. Leak pattern doğrulanırsa controlled snapshot alınır.
Incident Investigation
Runbook alert sonrası process report toplama adımını otomatikleştirebilir. Fatal error için `--report-on-fatalerror` gibi seçenekler artifact oluşturabilir. Report storage persistent olmalıdır çünkü container restart ephemeral file'ı silebilir. Sensitive environment veya network bilgisi policy'ye göre exclude edilebilir. Incident review report'un hangi bulguyu sağladığını belgelemelidir.
Production'da Memory Observability
Production memory observability tek bir RAM grafiğinden oluşmamalıdır. RSS, heapUsed, heapTotal, external memory, GC süresi ve event loop lag birlikte izlenmelidir. Request latency ve request rate aynı panelde yer alırsa memory pressure'ın kullanıcı etkisi anlaşılır. OOM ve restart count availability riskini gösterir. Bu metriklerin deployment version ve pod bazında filtrelenebilmesi memory regression tespitini hızlandırır.
RSS
RSS process toplam resident footprint'i için ana metriktir. Container limit yüzdesiyle birlikte gösterilmelidir. Uptime ile sürekli artış leak veya fragmentation sinyali olabilir. HeapUsed ve external breakdown sonraki teşhis adımını belirler. Pod bazlı grafikte tek replica anomalileri kolayca görülür.
Heap Used
HeapUsed JavaScript managed live allocation trendini gösterir. GC pattern nedeniyle raw grafik dalgalıdır. Rolling minimum veya GC sonrası baseline leak analizi için daha yararlıdır. Heap utilization heap size limit yüzdesi olarak da hesaplanabilir. Sustained yüksek utilization major GC riskini artırabilir.
Heap Total
HeapTotal V8'in mevcut heap capacity allocation'ını gösterir. HeapUsed artışıyla birlikte büyümesi normal olabilir. Yük altında genişleyip sonra sabit kalabilir. HeapUsed düşükken heapTotal yüksek kalması tek başına leak değildir. Runtime version değişikliğinde default behavior farklılaşabilir.
External Memory
External memory Buffer ve native-backed tracked allocation'lar hakkında sinyal verir. Binary workload servislerinde ayrı panel olmalıdır. HeapUsed normal fakat external artıyorsa diagnosis yönü değişir. ArrayBuffers alt metriği daha spesifik context verir. External limit için universal threshold yerine baseline deviation kullanılabilir.
GC Duration
GC duration histogram collector'ın kullanıcı latency üzerindeki potansiyel etkisini gösterir. Minor ve major GC mümkünse ayrı gözlenir. P99 GC pause memory pressure artışını erken gösterebilir. Node version upgrade sonrası baseline değişebilir. Alert yalnız tek uzun event yerine sustained pattern üzerinden tasarlanabilir.
Event Loop Lag
Event loop lag JavaScript execution'ın zamanında ilerleyemediğini gösterir. GC, synchronous CPU veya overloaded callback queue neden olabilir. Memory metric ile korelasyon root cause'u daraltır. Tek başına lag memory problemi demek değildir. P99 latency paneli kullanıcı etkisini tamamlar.
Request Latency
Memory pressure performance problemi oluşturuyorsa request tail latency genellikle etkilenir. P50, P95 ve P99 birlikte izlenmelidir. Major GC P99 spike üretirken average normal kalabilir. Route template bazlı breakdown hangi workload'ın memory pressure oluşturduğunu gösterebilir. Raw URL label kullanılmamalıdır.
OOM Count
OOM count sıfıra yakın tutulması gereken kritik reliability metriğidir. V8 OOM ve container OOM mümkünse ayrı sınıflandırılmalıdır. Tek OOM bile data processing job için önemli olabilir. Alert deployment ve pod context'ini taşımalıdır. OOM sonrası automatic restart incident'ı kapatmaz.
Restart Count
Restart count memory probleminin availability etkisini gösterir. Uptime kısa olan pod'larda leak trendi görünmeyebilir. Restart reason memory, crash veya rollout olarak ayrılmalıdır. Deployment restart'ları alarm noise oluşturmamalıdır. Unexpected restart budget SLO kapsamında sınırlandırılabilir.
Memory Alert'leri Nasıl Tasarlanmalıdır?
Memory alert yalnız “RSS 500 MB geçti” gibi tek sabit eşiğe dayanırsa farklı container boyutlarında anlamını kaybeder. Limit yüzdesi, sustained duration ve growth rate birlikte daha iyi sinyal sağlar. GC sonrası baseline artışı slow leak'i erken yakalayabilir. Multi-window alert kısa spike ile kalıcı pressure'ı ayırır. Alert mesajı pod, version, RSS, heap ve limit bilgisini beraber taşımalıdır.
Tek Bir Sabit MB Eşiğine Güvenmemek
512 MiB container ile 4 GiB container için aynı 400 MB alarmı farklı anlam taşır. Absolute değer capacity context'inden ayrı değildir. Service-specific normal baseline da farklı olabilir. Limit percentage ve historical baseline birlikte değerlendirilmelidir. Absolute threshold emergency hard stop için ikinci koruma olarak tutulabilir.
Container Limit Yüzdesi
RSS veya cgroup working set limitin yüzde kaçı kullanılıyor sorusu headroom'u gösterir. Yüzde 80 kısa spike normal olabilirken sustained yüzde 90 risklidir. Heap limit ayrı olduğundan V8 utilization da ayrıca izlenmelidir. Buffer-heavy servis için threshold daha erken olabilir. Historical OOM data tuning için kullanılır.
Sustained Threshold
Bir dakikalık upload spike alarm yaratmamalıdır. Memory 15 veya 30 dakika yüksek kalıyorsa daha anlamlı pressure sinyali oluşur. Duration workload karakterine göre belirlenir. Batch job doğal olarak uzun yüksek memory taşıyorsa ayrı alert policy gerekir. Service ve job type aynı threshold'u paylaşmak zorunda değildir.
Growth Rate
RSS'in MB/saat veya heap baseline'ın byte/request artışı slow leak'i hard threshold'tan önce gösterebilir. Growth rate smoothing ile noise azaltılmalıdır. Deployment sonrası initial warm-up interval hesap dışı bırakılabilir. Leak rate ve mevcut headroom kullanılarak tahmini OOM süresi hesaplanabilir. Bu incident önceliklendirmesini kolaylaştırır.
GC Sonrası Baseline
Raw heap grafiği sawtooth olduğu için baseline extraction daha anlamlı olabilir. GC event'leri biliniyorsa collection sonrası minimum kullanılır. Zaman içinde yükselen minimum leak sinyalidir. Forced GC production monitoring için kullanılmamalıdır. Statistical rolling low percentile alternatif olabilir.
Multi-Window Alert
Kısa pencere hızlı incident, uzun pencere slow leak yakalayabilir. Örneğin yüksek utilization kısa sürede critical, orta utilization uzun sürede warning üretebilir. Alert storm önlemek için deduplication uygulanmalıdır. Deploy sonrası temporary warm-up suppression dikkatle kullanılabilir. Alert root cause data linklerini dashboard ile birlikte sunmalıdır.
Leak Rate Nasıl Ölçülür?
Leak rate memory'nin zaman veya request başına ne kadar arttığını sayısallaştırır. MB/saat basit operational ölçümdür ancak trafik değişiyorsa yanıltıcı olabilir. Byte/request veya MB/1000 request traffic normalize edilmiş daha güçlü karşılaştırma sağlar. GC sonrası baseline kullanmak allocation noise'u azaltır. Bu değer fix öncesi ve sonrası aynı workload altında doğrudan karşılaştırılabilir.
MB/Saat
Uzun uptime servisinde RSS veya heap baseline slope MB/saat olarak hesaplanabilir. Slow leak için anlaşılır bir metric'tir. Trafik geceleri düşüyorsa slope de değişebilir. Uptime resetleri hesaplamada dikkate alınmalıdır. Tahmini time-to-OOM operasyon ekibine öncelik verir.
Byte/Request
Toplam baseline growth request sayısına bölünerek yaklaşık retained byte/request hesaplanabilir. Cache warm-up tamamlandıktan sonra ölçmek gerekir. Her request aynı endpoint değilse aggregate değer root cause'u gizleyebilir. Route bazlı synthetic test daha güvenilir olabilir. Yine de release regression comparison için kullanışlıdır.
MB/1000 Request
MB/1000 request daha okunabilir traffic-normalized unit sunar. Load testte sabit request count sonrası memory delta karşılaştırılabilir. GC timing noise'u azaltmak için uzun run tercih edilir. Baseline ve candidate aynı request distribution kullanmalıdır. Threshold historical healthy release üzerinden belirlenir.
Heap Baseline Growth
GC sonrası heap minimumları üzerinden linear trend çıkarılabilir. Positive sustained slope JavaScript retention ihtimalini gösterir. Cache limitine ulaşınca slope sıfıra yaklaşmalıdır. Snapshot points bu trend üzerindeki belirli zamanlara bağlanabilir. Heap baseline stable iken RSS büyüyorsa native investigation başlatılır.
Traffic Normalize Edilmiş Memory Growth
Request rate, active connection veya processed job sayısı memory growth denominator olarak kullanılabilir. WebSocket servisinde connection churn request count'tan daha anlamlı olabilir. Queue worker'da processed message sayısı tercih edilir. Doğru normalization workload modeline bağlıdır. Metric deployment version comparison'ı kolaylaştırmalıdır.
Kurumsal Memory SLO Nasıl Oluşturulur?
Memory SLO yalnız “OOM olmasın” hedefinden daha kapsamlı olmalıdır. Maximum RSS, heap utilization ve GC pause latency gibi ölçülebilir sınırlar belirlenebilir. OOM-free runtime ve restart budget availability hedefleriyle bağlanır. Minimum headroom traffic burst veya diagnostic operation için güvenlik payı sağlar. SLO deployment gate ve capacity planning kararlarına doğrudan girdi olmalıdır.
Maksimum RSS
Normal operation altında pod RSS'in container limitinin belirli yüzdesini aşmaması hedeflenebilir. Threshold workload benchmark üzerinden belirlenir. Peak ve sustained ayrı kurallar olabilir. Limit değiştiğinde SLO oran bazlı olduğu için anlamını korur. Native-heavy servis için daha fazla headroom gerekebilir.
Maximum Heap Utilization
HeapUsed veya used heap space'in heap size limit oranı izlenebilir. Uzun süre limitin çok yakınında çalışma frequent major GC riskini artırır. SLO sustained utilization üzerine kurulabilir. Short burst kabul edilebilir. Heap size limit runtime metric olarak doğru alınmalıdır.
GC Pause SLO
GC pause P99 belirli latency budget içinde tutulabilir. API toplam P99 hedefinin örneğin küçük bir kısmı collector'a ayrılır. Exact sayı workload ve user expectation'a göre seçilir. Node upgrade sonrası tekrar benchmark yapılır. GC telemetry yoksa event loop lag yardımcı proxy olabilir.
OOM-Free Runtime
Production workload için belirli dönem boyunca sıfır unexpected OOM hedeflenebilir. OOM event ciddi SLO violation kabul edilir. Planned stress environment bu metriğe dahil edilmez. Root cause ve corrective action incident review'da takip edilir. Aynı cause tekrar ediyorsa coding standard güncellenir.
Memory Headroom
Headroom current usage ile hard limit arasındaki boşluktur. Minimum headroom yüzdesi memory burst'lerine güvenlik sağlar. Heap, external ve container seviyesinde ayrı değerlendirilebilir. Diagnostic snapshot için gereken ek memory normal operating headroom'dan daha büyük olabilir. Bu nedenle snapshot replica drain sonrası gerekirse farklı memory class'ta çalıştırılabilir.
Restart Budget
Memory pressure nedeniyle process recycling sınırlı sayıda kabul edilebilir emergency event olabilir. Sürekli restart normal operation sayılmamalıdır. Budget service availability objective ile ilişkilendirilir. Restart reason classification doğru olmalıdır. Budget aşımı automatic issue veya incident tetikleyebilir.
Prometheus ile Node.js Memory Monitoring
Prometheus process ve application memory metriklerini zaman serisi olarak toplamak için yaygın bir model sunar. Node process RSS ve heap metrikleri standard collector veya custom instrumentation üzerinden export edilebilir. V8 heap space ve GC duration gibi detaylar ayrı metric aileleri oluşturabilir. Label cardinality kontrolü çok önemlidir. Metric naming, unit ve aggregation bütün servislerde ortak standarda bağlanmalıdır.
Process RSS
Process RSS gauge byte cinsinde export edilmelidir. Pod ve instance label investigation için yeterlidir. Container limit ile oran dashboard query'de hesaplanabilir. Alert sustained high ratio üzerinden çalışabilir. Worker cluster kullanılıyorsa process ayrımı korunmalıdır.
Heap Used
Heap used gauge JavaScript memory trendini gösterir. Heap size limit ile utilization ratio üretilebilir. Raw value sawtooth davranışı gösterir. Long window minimum veya low percentile leak analizi için yardımcıdır. Alert tek spike üzerinden çalışmamalıdır.
Heap Space
V8 space statistics space name label ile export edilebilir. Space isimleri finite olduğu için cardinality kontrollüdür. Runtime upgrade yeni space ekleyebilir. Dashboard unknown space'i drop etmemelidir. Old space growth investigation panelinde özellikle yararlıdır.
GC Metrics
GC event count ve duration histogram olarak izlenebilir. Collection type label sınırlı değer set'ine sahip olmalıdır. P95 veya P99 pause query edilebilir. GC rate allocation pressure hakkında fikir verir. Runtime instrumentation overhead benchmark edilmelidir.
Event Loop Metrics
Event loop lag veya utilization memory pressure'ın performans etkisini gösterir. GC spike ile lag korelasyonu dashboard'da görünür olmalıdır. CPU-bound work aynı metriği etkileyebilir. Bu nedenle memory root cause için tek başına yeterli değildir. Request P99 latency paneliyle birlikte değerlendirilir.
Custom Memory Metrics
Cache size, queue depth, active socket ve listener count application-specific leak sinyalleridir. Bu metrikler heap metric'ten daha erken root cause gösterebilir. Label cardinality bounded tutulmalıdır. Cache key veya user ID metric'e eklenmemelidir. Metric ownership ilgili component code'unda açık olmalıdır.
Grafana Memory Dashboard Nasıl Tasarlanır?
İyi bir Grafana memory dashboard incident sırasında farklı ekranlar arasında dolaşma ihtiyacını azaltır. RSS, heapUsed, GC duration, request rate ve P99 latency aynı zaman ekseninde gösterilmelidir. Container limit çizgisi headroom'u görsel hâle getirir. Restart count ve deployment annotation memory reset noktalarını açıklar. Pod bazlı ve service aggregate görünümler arasında kolay geçiş sağlanmalıdır.
RSS per Pod
Her pod ayrı series olarak gösterildiğinde tek replica leak'i hemen fark edilir. Çok fazla pod varsa top N veya anomaly view kullanılabilir. Deployment version legend'de yer alabilir. Uptime bilgisi leak slope yorumunu kolaylaştırır. Restart sonrası series reset'i görünür olmalıdır.
Heap Used per Pod
HeapUsed RSS ile aynı panel veya hemen altında bulunmalıdır. RSS artarken heap stable ise diagnosis yönü değişir. Heap limit horizontal line eklenebilir. GC sonrası düşüşler grafikte görülür. Baseline release comparison için time shift kullanılabilir.
GC Duration
GC duration histogram quantile paneli P95 ve P99 değerlerini gösterir. Major GC count ayrı series olabilir. Heap utilization yükselirken pause artıyorsa strong correlation oluşur. Node version annotation runtime değişikliğini gösterir. Alert threshold SLO ile uyumlu olmalıdır.
Request Rate
Memory growth traffic olmadan yorumlanmamalıdır. Request rate aynı dashboard'da görünür olmalıdır. Traffic spike ile temporary heap growth kolayca ayrılır. Route-level breakdown gerekiyorsa low-cardinality template kullanılır. Request rate düşerken memory yükselmeye devam ediyorsa background leak araştırılır.
P99 Latency
P99 memory pressure'ın kullanıcı etkisini gösterir. GC pause veya event loop stall ile aynı timestamp'teki spike araştırılır. Route group bazında farklılık olabilir. Tail latency SLO breach alert memory dashboard'a link vermelidir. Memory optimization yalnız RAM tasarrufu değil latency iyileştirmesi olarak ölçülebilir.
Container Memory Limit
Limit statik horizontal line veya ratio paneli olarak gösterilebilir. Deployment manifest değişirse panel otomatik yeni değeri almalıdır. RSS yanında working set de gerekirse eklenir. Headroom yüzde olarak ayrı stat göstergesi olabilir. Limit bulunmayan container production policy violation olarak alarm üretebilir.
Restart Count
Restart memory graph reset noktalarını açıklar. OOMKilled ve rollout restart mümkünse ayrı annotation almalıdır. Artan restart memory leak'i görünmez kılabilir. Pod uptime paneli bunu tamamlar. Unexpected restart count release health dashboard'unda da bulunmalıdır.
APM Araçları Bellek Tüketir mi?
APM agent application içine instrumentation, span buffer ve exporter queue eklediği için belirli CPU ve memory overhead oluşturabilir. Bu overhead agent, sampling rate ve traffic miktarına göre değişir. Memory incident'ta APM agent'ın kendisi de deneyle doğrulanmalıdır. APM açık ve kapalı aynı load testi karşılaştırılabilir. Observability kazanımı ile resource maliyeti ölçülerek configuration yapılmalıdır.
Instrumentation Overhead
Her request hook, context propagation ve span object allocation oluşturabilir. Düşük rate'te önemsiz olan maliyet yüksek RPS'te büyür. Agent version upgrade memory regression testine dahil edilmelidir. Profiling feature'ları ekstra overhead getirebilir. Production sampling policy ihtiyaca göre ayarlanmalıdır.
Trace Buffer
Span'lar exporter göndermeden önce memory buffer'da tutulabilir. Backend unavailable olduğunda buffer büyüme davranışı kritik hâle gelir. Maximum queue size olmalıdır. Drop policy application OOM olmadan telemetry kaybını tercih edebilir. Exporter metrics queue saturation'ı göstermelidir.
Span Queue
Async exporter span batch'lerini queue'da tutar. Sınırsız queue observability component'ini leak kaynağına dönüştürebilir. Max queue size ve batch size configuration review edilmelidir. Network outage load testte simüle edilebilir. Telemetry failure business request'i bloklamamalıdır.
Sampling
Sampling oluşturulan veya exported trace sayısını sınırlar. Düşük sampling memory ve network overhead'i azaltabilir. Error veya high latency request için tail sampling farklı ihtiyaç taşır. Sampling configuration incident visibility'yi tamamen yok etmemelidir. Rate traffic hacmine göre belirlenmelidir.
Agent Benchmark
APM agent eklenmeden önce ve sonra aynı load çalıştırılmalıdır. RSS, heap, CPU ve P99 latency karşılaştırılır. Agent startup baseline memory de ölçülür. Feature bazlı profiling veya log injection ayrı ayrı açılarak impact bulunabilir. Sonuç upgrade decision'a girdi olur.
APM Açık/Kapalı Memory Karşılaştırması
Aynı container ve workload iki configuration ile test edilir. Warm-up sonrası stable RSS farkı kaydedilir. Leak yalnız APM açıkken görülüyorsa agent veya instrumentation interaction araştırılır. Dependency version bisect kullanılabilir. Agent'ı kalıcı kapatmak yerine root cause veya configuration düzeltmesi hedeflenmelidir.
Logging Memory Kullanımını Nasıl Artırabilir?
Async logger request thread'ini bloklamamak için log event'lerini memory queue'da tutabilir. Log destination yavaşladığında bu queue büyüyebilir. Büyük object veya request body loglamak hem serialization hem queue memory maliyetini artırır. Debug log flood production incident sırasında memory problemini daha da kötüleştirebilir. Logging pipeline için de backpressure, maximum buffer ve drop policy tanımlanmalıdır.
Async Logging Queue
Logger event'leri background worker'a göndermek için queue kullanabilir. Destination unavailable olduğunda queue'nun davranışı bilinmelidir. Sınırsız buffer application heap'ini tüketebilir. Maximum queue ve overflow policy configuration'da açık olmalıdır. Dropped log count metric olarak izlenebilir.
Büyük Log Object
Tüm request veya response object'ini loglamak büyük allocation oluşturur. Logger serializer object'i kopyalayabilir veya stringify edebilir. Sensitive data riski ayrıca oluşur. Structured log yalnız gerekli küçük field set'ini taşımalıdır. Payload size metric body content'inden daha güvenlidir.
Circular Serialization
Request object gibi complex structure circular reference içerebilir. Generic JSON serialization hata verebilir veya özel serializer çok fazla traversal yapabilir. Logger library safe serializer kullansa bile CPU ve memory maliyeti olabilir. Native request object'i loglamamak daha iyi yaklaşımdır. Method, route, status ve requestId çoğu incident için yeterlidir.
Buffering
Buffered logging disk veya network verimliliğini artırabilir. Buffer capacity bounded değilse sink outage sırasında memory büyür. Flush interval çok uzun seçilirse peak buffer artar. Shutdown sırasında flush için timeout gerekir. Log loss ile availability arasında açık öncelik policy belirlenmelidir.
Log Transport Backpressure
Remote log transport consumer yavaşsa producer log rate'i aşabilir. Application request'lerini bloklamak veya memory'de sınırsız bekletmek iki uç risktir. Drop, sampling veya local bounded buffer uygulanabilir. Transport health metric dashboard'da gösterilmelidir. Logging backend incident application OOM'a dönüşmemelidir.
Debug Log Flood
Debug level production'da her request için büyük log üretebilir. Incident sırasında geçici açılacaksa süre ve scope sınırlandırılmalıdır. Single pod veya route için sampling tercih edilebilir. Log volume alert'i yanlış configuration'ı erken gösterir. Feature otomatik expiry ile kapanabilir.
Source Map'lerin Memory Etkisi
Source map production stack trace'lerini okunabilir hâle getirerek debugging deneyimini iyileştirir. Bazı error tracking veya runtime tooling source map dosyalarını parse edip cache'leyebilir. Büyük bundle ve yoğun stack processing memory overhead'i oluşturabilir. Etki toolchain ve configuration'a göre değişir. Source map açık ve kapalı benchmark memory-sensitive servislerde faydalı olabilir.
Production Source Maps
Source map deployment artifact içinde tutulabilir veya yalnız error tracking backend'e yüklenebilir. Public olarak serve edilmesi source exposure riski oluşturabilir. Runtime'ın map'leri memory'de tutup tutmadığı kullanılan tooling'e bağlıdır. Large map file tek başına heap leak anlamına gelmez. Error volume arttığında map processing overhead'i artabilir.
Stack Trace
Stack trace error investigation için kritiktir. Çok yüksek exception rate sürekli stack capture ve formatting maliyeti oluşturabilir. Expected validation flow için exception-heavy design CPU ve memory overhead yaratabilir. Error aggregation duplicate stack loglarını azaltır. Source map processing yalnız gerekli error seviyesinde uygulanabilir.
Source Map Cache
Error tooling parsed source map'leri cache'leyebilir. Cache bounded değilse çok sayıda dynamic bundle veya version memory büyümesi oluşturabilir. Normal server application'da bundle version sayısı sınırlı olmalıdır. Agent documentation memory behavior açısından incelenmelidir. Release sonrası old map cache'in silindiği doğrulanabilir.
Debugging vs Memory Trade-Off
Source map faydası incident resolution süresini ciddi azaltabilir. Küçük memory overhead çoğu service için kabul edilebilir olabilir. Memory-sensitive worker'da ise optimize configuration gerekebilir. Karar varsayımla değil benchmark ile verilmelidir. Security ve operational fayda da aynı değerlendirmeye dahil edilmelidir.
Memory Regression Testi Nedir?
Memory regression testi yeni application sürümünün aynı workload altında önceki sağlıklı sürüme göre daha fazla memory büyümesi oluşturup oluşturmadığını ölçer. Baseline ve candidate aynı environment, warm-up ve request sequence ile çalıştırılır. Test sonu yalnız peak RSS değil GC sonrası heap baseline da karşılaştırılabilir. Allowed growth threshold historical variance üzerinden belirlenmelidir. Büyük regression CI/CD pipeline'ı fail ederek production incident oluşmadan durdurulabilir.
Baseline Version
Baseline son bilinen sağlıklı production veya release candidate sürüm olmalıdır. Aynı dependency lock ve runtime environment kaydedilir. Memory ölçümü birkaç tekrar alınarak doğal variance belirlenir. Baseline çok eski olursa unrelated değişiklikler karşılaştırmayı zorlaştırır. Her major release yeni baseline oluşturabilir.
Candidate Version
Candidate yeni code veya dependency değişikliklerini içerir. Aynı container memory limit ve Node version kullanılmalıdır. Runtime upgrade test ediliyorsa yalnız Node version değişken olarak bırakılabilir. Warm-up procedure birebir aynı olmalıdır. Fail durumunda allocation profile candidate üzerinde alınabilir.
Aynı Load
Request sayısı, payload, key cardinality ve concurrency iki sürümde eşit olmalıdır. Random input seeded generator ile kontrol edilebilir. External dependency latency değişirse test sonucu bozulabilir. Mock veya dedicated test dependency daha deterministik olabilir. Memory test load script'i version control altında tutulmalıdır.
Warm-Up
Module load ve cache initialization tamamlanmadan measurement başlatılmamalıdır. Baseline ve candidate aynı warm-up request set'ini almalıdır. Warm-up sonunda memory metric snapshot kaydedilir. Test delta bu noktadan hesaplanır. JIT ve connection pool behavior için yeterli süre bırakılmalıdır.
GC Sonrası Measurement
Test ortamında karşılaştırma için controlled GC bazı özel senaryolarda kullanılabilir. Ancak production runtime behavior'ı tamamen temsil etmez. Alternatif olarak test bittikten sonra settle period ve doğal GC beklenebilir. Aynı procedure iki version'da uygulanmalıdır. Raw peak ve post-GC baseline birlikte kaydedilebilir.
Allowed Growth Threshold
Sıfır byte fark gerçekçi değildir. V8, dependency ve timing doğal variance oluşturabilir. Historical test dağılımına göre percentage veya absolute threshold belirlenmelidir. Büyük input değişikliği ayrı benchmark gerektirir. Threshold aşımı automatic investigation artifact üretebilir.
CI/CD'de Memory Testleri Nasıl Yapılır?
CI/CD memory testi application'ı kontrollü resource limit ile başlatıp deterministik load çalıştırabilir. Başlangıç, warm-up ve test sonu memory değerleri kaydedilir. Baseline sürümle fark threshold'u aşarsa pipeline fail edilebilir. Kısa test fast regression yakalarken scheduled soak test yavaş leak'leri bulur. Profiling artifact yalnız failure durumunda saklanarak storage maliyeti azaltılabilir.
Application Başlatmak
Test container production'a benzer Node version ve startup flags ile çalışmalıdır. Memory limit açıkça belirlenir. Application health ready olduktan sonra warm-up başlar. Startup logs heap size limit bilgisini kaydedebilir. Test sonunda exit ve resource cleanup kontrol edilir.
Load Generator
Load generator application process'ten ayrı çalışmalıdır. Aynı host üzerinde memory contention test sonucunu bozabilir. Request sequence deterministic tutulmalıdır. Payload production distribution'ını temsil etmelidir. Generator error'ları test fail olarak ele alınmalıdır.
Sabit Request Sayısı
Örneğin her version aynı 100 bin request'i işleyebilir. Duration machine performance'a göre değişse bile retained byte/request karşılaştırılabilir. Concurrent request sayısı da sabit tutulmalıdır. Cache key cardinality kontrollü olmalıdır. Route mix production'a benzer ağırlıklarda seçilebilir.
Memory Baseline
Warm-up sonu RSS ve heapUsed baseline kaydedilir. External ve listener count da alınabilir. Baseline tek sample yerine kısa window average veya minimum olabilir. Test runner metric dosyasını artifact olarak saklar. Candidate delta bu değerden hesaplanır.
Test Sonu Memory
Load bittikten sonra belirli settle süresi verilir. Memory tekrar ölçülür. Peak RSS ayrıca kaydedilir çünkü transient regression OOM riski yaratabilir. End baseline leak, peak ise burst riskini gösterir. İki metric ayrı threshold alabilir.
Threshold
Threshold previous healthy release variance'ından türetilmelidir. Sabit 5 MB her project için uygun değildir. Percentage ve absolute değer birlikte kullanılabilir. External memory regression ayrıca kontrol edilebilir. Threshold değişikliği review gerektirmelidir.
Regression'da Pipeline'ı Fail Etmek
Büyük ve reproducible regression production'a geçmemelidir. Pipeline failure heap profile veya metric summary link'i sağlamalıdır. Developer local reproduction command'ı almalıdır. Flaky threshold sürekli bypass edilmemelidir. Test reliability önce iyileştirilmelidir.
Soak Test Nedir?
Soak test application'ı uzun süre sabit veya gerçekçi trafik altında çalıştırarak yavaş biriken resource problemlerini bulur. Kısa load test saniyede yüksek throughput görür ancak saat başına 2 MB leak'i fark etmeyebilir. Memory baseline, listener count, connection count ve queue depth test boyunca izlenir. Growth rate hesaplanır. Production release öncesi kritik backend'ler için scheduled soak test yüksek değer sağlar.
Kısa Load Test'in Yakalamadığı Leak'ler
Request başına 100 byte retention on bin request'te yalnız bir megabyte eder. Kısa testte noise içinde kaybolabilir. Saatler süren test milyonlarca request ile trend'i belirginleştirir. Slow timer veya TTL bug'ları da uzun sürede ortaya çıkar. Soak test bu yüzden peak benchmark'ın yerini değil tamamlayıcısını alır.
Saatler Süren Trafik
Test birkaç saat veya workload gerektiriyorsa daha uzun çalışabilir. Environment cost ve test süresi dengelenmelidir. Scheduled nightly pipeline uygun olabilir. Application version ve Node runtime değişkenleri kaydedilir. Test sırasında external dependency instability sonucu etkilememelidir.
Sabit RPS
Sabit RPS growth rate hesaplamasını kolaylaştırır. Daha gelişmiş senaryoda daily traffic pattern simüle edilebilir. İlk leak isolation için constant load daha deterministiktir. Error rate yükselirse result invalid olabilir. Generator'ın kendi resource limiti de izlenmelidir.
Heap Baseline
HeapUsed low points zaman içinde kaydedilir. Upward linear trend retained object birikimini gösterebilir. Cache warm-up phase analysis dışında bırakılır. Baseline plateau oluşması beklenir. Candidate ve baseline release trendleri karşılaştırılır.
Listener Count
Kritik emitter listener count soak boyunca stabil kalmalıdır. Active connection sayısıyla birlikte yorumlanır. Connection churn bittiğinde count başlangıç seviyesine yaklaşmalıdır. Sürekli artış cleanup bug'ına işaret eder. Warning çıkmasını beklemek zorunda kalmadan metric leak'i gösterebilir.
Connection Count
Database ve socket connection sayıları workload ile orantılı ama bounded olmalıdır. Request sayısıyla birlikte sürekli büyüyen open connection leak göstergesidir. Pool metrics bunu kolayca ortaya çıkarır. Idle connection policy test boyunca çalışmalıdır. Test sonunda kaynak sayıları baseline'a dönmelidir.
Memory Growth Rate
RSS ve heap slope soak testin ana çıktılarındandır. MB/saat ve byte/request birlikte raporlanabilir. Stable heap fakat RSS growth native veya fragmentation investigation tetikler. Threshold history üzerinden belirlenir. Fix sonrası aynı duration ve RPS tekrar çalıştırılır.
Memory Testlerinde global.gc() Kullanılmalı mı?
`global.gc()` yalnız Node.js `--expose-gc` seçeneğiyle explicit erişime açıldığında kullanılabilir. Production application'ın normal behavior'ını yönetmek için sürekli forced GC çağrısı önerilmez. Garbage collector ne zaman çalışacağını runtime heuristics ile belirler. Test ortamında iki sürümün post-GC retained heap'ini karşılaştırmak için kontrollü kullanım yararlı olabilir. Ancak sonuç gerçek runtime latency ve collection frequency davranışının yerine geçmez.
--expose-gc
Flag V8 garbage collector'ı JavaScript tarafından manuel tetikleme imkanını expose eder. Normal production application buna ihtiyaç duymamalıdır. Memory regression testinde warm-up ve workload sonrası controlled sample alınabilir. Flag'in aktif olması yanlışlıkla business code içinde GC call kullanılmasına yol açmamalıdır. Test-only configuration ayrı tutulmalıdır.
Forced GC'nin Production Kullanımı
Request başına veya interval ile forced GC çalıştırmak latency spike oluşturabilir. Runtime'ın kendi generational heuristics'i bozulabilir. Leak varsa referanslar hâlâ reachable olduğu için forced GC problemi çözmez. Memory düşüşü geçici olursa yanlış güven yaratabilir. Production tuning allocation ve memory budget üzerinden yapılmalıdır.
Test Ortamında Baseline Karşılaştırması
Controlled GC iki candidate arasında garbage collection timing noise'unu azaltabilir. Aynı call sayısı ve timing uygulanmalıdır. Baseline sonrası retained heap daha doğrudan karşılaştırılır. Peak memory yine ayrı ölçülmelidir. Test sonucu production soak ile tamamlanmalıdır.
Gerçek Runtime Davranışını Bozmamak
Her minute forced GC yapılan test production'a benzemez. Collector frequency ve pause metrics yanlış görünür. Regression test yalnız final measurement öncesi tek controlled GC kullanabilir. Başka test ise tamamen doğal GC ile çalışmalıdır. İki sonuç birlikte daha güvenilir picture sağlar.
Node.js Sürüm Güncellemelerinde Memory Benchmark
Node.js major veya LTS update yalnız syntax ve security değişikliği değildir, beraberinde yeni V8 sürümü ve garbage collection davranışı da getirir. Aynı application yeni runtime üzerinde farklı baseline heap veya RSS gösterebilir. Dependency native addon compatibility ayrıca kontrol edilmelidir. Upgrade canary öncesi aynı load testi iki runtime üzerinde çalıştırılmalıdır. Memory regression ve P99 latency birlikte değerlendirilmelidir.
V8 Sürümü Değişimi
Node.js major update yeni V8 version getirebilir. Heap space implementation ve GC heuristics zaman içinde değişebilir. Eski tuning flag'i yeni version'da aynı sonucu vermeyebilir. Runtime heap size limit yeniden ölçülmelidir. Performance release notes önemli değişiklikler açısından incelenmelidir.
GC Davranışı
Yeni V8 minor ve major collection timing'ini değiştirebilir. Aynı workload daha az RSS veya farklı pause pattern gösterebilir. Bu değişiklik otomatik olarak regression değildir. SLO ve memory budget sonuçlarına göre değerlendirilir. GC metric dashboard rollout sırasında version label ile karşılaştırılır.
Dependency Uyumluluğu
Native addon'lar Node ABI veya Node-API uyumluluğu açısından test edilmelidir. Unsupported addon crash veya memory issue oluşturabilir. Package lock temiz environment'ta install edilmelidir. Dependency test suite yeni Node version'da çalıştırılır. EOL runtime'a bağlı package varsa upgrade planı öncelik kazanır.
Baseline Load Test
Eski ve yeni Node version aynı application commit ile test edilmelidir. Böylece runtime etkisi izole edilir. RSS, heap, GC ve latency karşılaştırılır. Test birkaç kez tekrar edilerek noise ölçülür. Büyük fark varsa profiler ile nedeni araştırılır.
Memory Regression
Yeni runtime stable heap'i önemli ölçüde artırabilir veya azaltabilir. Container density etkilenebilir. Regression kabul edilecekse memory request ve limit yeniden sizing yapılmalıdır. Unexpected growth upstream issue veya dependency interaction olabilir. Canary production gerçek traffic'te son doğrulamayı sağlar.
Canary Deployment
Yeni Node version önce az sayıda replica üzerinde çalıştırılabilir. Traffic küçük yüzdesi canary'ye yönlendirilir. Memory baseline, GC ve latency stable release ile karşılaştırılır. Leak rate veya OOM oluşursa rollout durdurulur. Canary yeterli uptime görmeden full rollout yapılmamalıdır.
Production Node.js İçin Hangi Sürüm Kullanılmalı?
Production uygulamalarında Node.js projesinin destek politikasına göre Active LTS veya Maintenance LTS sürümleri tercih edilmelidir. 23 Ağustos 2026 itibarıyla Node.js 24 LTS hattındadır, Node.js 26 Current durumundadır ve Node.js 20 artık EOL durumundadır. Current sürüm yeni özellikleri daha erken sunabilir fakat kurumsal production için LTS hattı daha öngörülebilir seçimdir. Sürüm seçimi yalnız major numaraya göre değil security support, dependency compatibility ve benchmark sonucuna göre yapılmalıdır. Upgrade politikası EOL tarihinden aylar önce planlanmalıdır.
Current
Current sürüm en yeni runtime özelliklerini ve V8 değişikliklerini içerir. Library maintainer ve early adopter için değerlidir. Production kullanımı organization risk appetite'a göre mümkündür fakat LTS kadar uzun destek dönemi sunmaz. Dependency compatibility daha yakından izlenmelidir. Canary ve rollback planı zorunlu olmalıdır.
LTS
LTS hattı uzun süre destek ve kritik fix beklentisi nedeniyle production için uygun default'tur. Node.js resmi release sayfası production application'ların desteklenen LTS hatlarını kullanmasını önerir. LTS olmak memory regression olmayacağı garantisi değildir. Her patch ve minor update test pipeline'dan geçmelidir. Runtime image düzenli güncellenmelidir.
Maintenance LTS
Maintenance LTS hâlâ desteklenen ancak lifecycle'ın daha ileri aşamasındaki sürümdür. Yeni project için daha güncel Active LTS çoğu zaman daha uzun migration runway sağlar. Existing application maintenance LTS üzerinde kalabilir ancak EOL planı önceden yapılmalıdır. Security patch takibi sürdürülmelidir. Dependency support trend'i gözlenmelidir.
EOL Sürümlerin Riski
EOL runtime artık normal security ve bug fix desteği almaz. Ecosystem package'leri bu version desteğini zamanla kaldırabilir. Native library ve OS compatibility riski artar. Memory veya crash bug'ı için upstream fix alma ihtimali düşer. Production policy EOL runtime deployment'ını engellemelidir.
Kurumsal Upgrade Politikası
Organization yılda belirli Node upgrade window'ları tanımlayabilir. EOL tarihinden önce target LTS seçilir. Dependency, memory regression ve load test otomatik çalıştırılır. Canary rollout birkaç gün veya workload cycle boyunca izlenir. Rollback image hazır tutulur.
Memory Leak Üçüncü Taraf Paketten Kaynaklanıyorsa Ne Yapılmalı?
Memory leak application code'dan değil dependency içindeki listener, cache veya native allocation bug'ından kaynaklanabilir. İlk adım version bisect ile problemin hangi release'te başladığını daraltmaktır. Minimal reproduction package maintainer için çok değerlidir. Update veya güvenli downgrade kısa vadede çözüm sağlayabilir. Gerekirse küçük patch fork uygulanabilir fakat uzun süreli internal fork bakım maliyeti yaratır.
Dependency Version Bisect
Known-good ve bad version arasındaki package release'leri test edilir. Aynı soak workload her version'da çalıştırılır. Memory growth rate sonucu kaydedilir. Problem introduction version bulunduğunda changelog ve commit diff incelenir. Transitive dependency değişiklikleri de hesaba katılmalıdır.
Minimal Reproduction
Application'ın tamamı yerine yalnız problemli package ve birkaç satır workload içeren küçük repo hazırlanır. Sensitive company code çıkarılır. Memory trend veya snapshot evidence eklenir. Node version ve OS belirtilir. Maintainer'ın bug'ı hızlı reproduce etmesi çözüm ihtimalini artırır.
Package Update
Yeni version leak fix içeriyorsa staging regression test yapılır. Breaking changes ayrıca kontrol edilir. Update sonrası memory slope gerçekten düzelmelidir. “Issue closed” bilgisi tek başına production proof değildir. Canary rollout devam etmelidir.
Downgrade
Leak yeni package version ile başladıysa known-good version'a downgrade emergency mitigation olabilir. Security fix kaybı olup olmadığı kontrol edilmelidir. Lockfile version'ı explicit tutar. Downgrade root cause raporuna geçici action olarak yazılır. Upstream fix geldiğinde tekrar upgrade planlanır.
GitHub Issue
Issue minimal reproduction, version matrix ve memory evidence içermelidir. Heap snapshot içinde sensitive data varsa public olarak paylaşılmamalıdır. Constructor growth veya sample profile anonymized biçimde verilebilir. Maintainer'ın istediği ek diagnostic staging üzerinde üretilir. Teknik ve tekrarlanabilir issue topluluk için de faydalıdır.
Geçici Workaround
Feature flag ile problemli code path kapatılabilir. Worker recycling veya cache clear yalnız emergency mitigation olabilir. Workaround kullanıcı impact ve security riskine göre seçilmelidir. Geçici çözüm için expiry date ve owner atanmalıdır. Aksi hâlde yıllarca kalıcı architecture'ya dönüşebilir.
Fork
Upstream fix gecikiyorsa controlled internal fork düşünülebilir. Patch minimal tutulmalı ve upstream PR ile senkronlanmalıdır. Security update'leri takip etmek için owner gerekir. Fork uzun vadede upgrade maliyetini artırır. Mümkün olan ilk stabil upstream release'te geri dönülmelidir.
Native Addon Memory Leak Nasıl Tespit Edilir?
Native addon leak'inde JavaScript heapUsed çoğu zaman normal görünürken RSS yükselmeye devam eder. External memory bazı addon allocation'larını yansıtabilir ancak her native allocation orada görünmeyebilir. Bu nedenle heap snapshot tek başına yeterli değildir. Dependency isolation ve native profiler kullanılarak allocation source daraltılır. Minimal reproduction addon maintainer'a iletilebilecek en değerli kanıttır.
heapUsed Sabit
Stable heapUsed classic JS object leak ihtimalini azaltır. RSS growth devam ediyorsa process heap dışı alanlara bakılır. Heap snapshot comparison'da anlamlı constructor growth görülmeyebilir. External ve arrayBuffers sonraki adımlardır. Native addon feature toggle ile A/B test yapılabilir.
RSS Büyüyor
Native allocation process RSS'e doğrudan katkı sağlar. Traffic ile sürekli artan RSS leak rate olarak ölçülebilir. Idle sonrası geri dönmemesi retention veya fragmentation ihtimalini güçlendirir. Process restart değeri sıfırlar. Long soak root cause trend'ini belirginleştirir.
external Memory
Addon V8 external memory accounting API'sini kullanıyorsa external metric artabilir. Bu davranış implementation'a bağlıdır. External stable olması native leak olmadığını garanti etmez. ArrayBuffer-backed addon daha görünür olabilir. Metric yalnız hypothesis yönlendirmelidir.
Native Profiler
Operating system ve compiler ecosystem'ine uygun memory profiler allocation stack'lerini gösterebilir. Production üzerinde overhead yüksek olabilir. Reproduction staging'e taşınmalıdır. Debug symbols analysis kalitesini artırabilir. Tool output source code call site ile eşleştirilmelidir.
Minimal Reproduction
Addon API aynı loop içinde tekrar çağrılarak leak hızlandırılabilir. JavaScript framework dependency'leri kaldırılır. RSS ve heapUsed her iterasyonda kaydedilir. Leak yalnız addon call ile devam ediyorsa evidence güçlenir. Reproduction upstream issue'ya eklenebilir.
Dependency Isolation
Feature flag ile addon kullanan code path kapatılır. Aynı load iki build üzerinde karşılaştırılır. RSS growth yalnız addon açıkken ortaya çıkıyorsa cause daralır. Transitive native dependency ayrıca incelenebilir. Version bisect fix bulunan release'i gösterebilir.
Linux'ta RSS Fragmentation Problemi
Linux ve özellikle glibc `malloc` kullanılan sistemlerde process RSS heap memory sabit görünse bile fragmentation nedeniyle yüksek kalabilir. Node.js resmi process documentation bu davranışa özel olarak dikkat çeker. Bu durum gerçek leak ile karıştırılabilir. HeapUsed, external ve allocation workload stabil olduğu hâlde RSS upward drift gösteriyorsa allocator araştırılır. Allocator değişikliği production'a alınmadan önce compatibility ve benchmark yapılmalıdır.
glibc malloc
glibc Linux dağıtımlarında yaygın memory allocator'dır. Farklı thread ve allocation pattern'leri arena davranışı nedeniyle fragmentation oluşturabilir. Serbest bırakılan alan process içinde kalıp OS'e dönmeyebilir. Bu durum workload'a bağlıdır. Native allocation benchmark glibc davranışını ölçebilir.
Heap Sabitken RSS Artışı
HeapUsed ve heapTotal aynı bantta kalırken RSS'in yavaş yükselmesi fragmentation sinyalidir. External memory de stable ise hypothesis güçlenir. Uygulama idle olduğunda RSS düşmeyebilir. Bu her durumda allocator problemi değildir. Native addon leak'i aynı pattern'i oluşturabileceği için profiling gerekir.
Leak ile Fragmentation'ı Ayırmak
Leak'te allocated canlı data zaman içinde artar. Fragmentation'da logical live data stable olabilir. Native allocation profiler active block miktarını gösterebilir. Workload durduğunda application state count sabit kalır. Farklı allocator ile aynı test sonucu güçlü karşılaştırma sağlar.
Allocator Davranışı
Allocator freed block'ları future allocation için saklayabilir. Thread arenas memory'nin parçalı kalmasına neden olabilir. OS'e release policy version ve configuration'a göre değişebilir. Application code düzeltmesi her fragmentation sorununu çözmez. Infrastructure-level change dikkatli rollout gerektirir.
Benchmark
Default ve alternatif allocator aynı binary ve workload ile test edilmelidir. RSS, CPU, throughput ve latency birlikte ölçülür. Yalnız düşük RSS için CPU regression kabul edilmemelidir. Native module compatibility doğrulanır. Canary rollout production traffic üzerinde son kontrolü sağlar.
Memory Problemlerinde Restart Çözüm müdür?
Restart process memory state'ini sıfırladığı için memory problemine hızlı rahatlama sağlayabilir. Ancak unbounded cache, listener leak veya native bug aynı kodla yeniden başlayacaktır. Restart emergency mitigation ve planned recycling için kullanılabilir. Kalıcı solution root cause'u ortadan kaldırmaktır. Restart interval kısalıyorsa problem reliability incident olarak büyüyor demektir.
Symptom'u Geçici Olarak Sıfırlamak
Process restart bütün in-memory object graph'ını ve native allocations'ı işletim sistemine bırakır. Memory grafiği aniden düşer. Bu görüntü leak'in çözüldüğü anlamına gelmez. Uptime ile memory slope yeniden başlamalıdır. Dashboard restart annotation olmadan yanıltıcı olabilir.
Root Cause'u Çözmemek
Leak code path devam ettiği sürece aynı retention tekrar oluşur. Daha sık restart yalnız failure period'unu değiştirir. Incident RCA leak rate ve retaining path bulmalıdır. Fix sonrası restart frequency normal deployment seviyesine dönmelidir. Automated recycling geçici action olarak issue'da açık kalmalıdır.
Planned Worker Recycling
Bazı long-running workload'lar third-party native library nedeniyle kontrollü worker recycling kullanabilir. Worker belirli job sayısı veya memory threshold sonrası yenilenir. Bu architecture deliberate isolation sağlar. Yine de library leak'i mümkünse upstream çözülmelidir. Recycling rate capacity ve latency üzerinde benchmark edilmelidir.
Emergency Mitigation
OOM riski yüksek incident'ta rolling restart availability'yi geçici koruyabilir. Önce diagnostic evidence toplanmalıdır. Çok hızlı restart dump alma fırsatını kaybettirebilir. One replica drain edilip investigation için ayrılabilir. Mitigation ve permanent fix ayrı incident action olarak takip edilmelidir.
Restart Loop Riski
Memory startup sırasında hızla büyüyorsa process saniyeler içinde tekrar OOM olabilir. Orchestrator sürekli restart ederek load ve downstream pressure artırabilir. Backoff policy gerekir. Readiness yeni process gerçekten hazır olmadan trafik almamalıdır. Rollback daha güvenli çözüm olabilir.
Memory Incident Runbook Nasıl Oluşturulur?
Memory incident runbook alarm geldiğinde hangi metric'e bakılacağını ve hangi diagnostic aracın hangi koşulda kullanılacağını önceden tanımlar. İlk amaç availability'yi korumak ve root cause evidence'i kaybetmemektir. Etkilenen pod belirlenir, trafik drain edilir ve memory breakdown incelenir. Snapshot yalnız yeterli headroom varsa alınır. Restart sonrası RCA, regression test ve corrective action tamamlanır.
Alert
Alert pod, deployment version, RSS, heapUsed ve container limit bilgisini içermelidir. Growth rate varsa tahmini OOM süresi eklenebilir. Dashboard link'i investigation'ı hızlandırır. Alert severity headroom ve user impact'e göre belirlenir. Tek kısa spike paging oluşturmamalıdır.
Etkilenen Pod/Process'i Belirlemek
Aggregate service metric tek problemli replica'yı gizleyebilir. Pod bazlı RSS ve uptime karşılaştırılır. Yeni deployment veya belirli zone korelasyonu kontrol edilir. Cluster worker kullanılıyorsa process PID breakdown gerekir. Leak gösteren process diagnostic target olarak seçilir.
Traffic Drain
Replica readiness kapatılır. In-flight request'lerin tamamlanması beklenir. WebSocket connection policy ayrıca uygulanır. Drain sonrası memory düşüşü observation için kaydedilir. Diagnostic operation user traffic'i etkilemeden yapılabilir.
Memory Metrics
HeapUsed, external, arrayBuffers ve RSS birlikte açılır. GC duration ve event loop lag kullanıcı impact'i gösterir. Cache, queue ve connection metrics root cause candidate'lerini daraltır. Deployment timestamp trend başlangıcıyla karşılaştırılır. Incident notes bu snapshot'ı kayıt altına alır.
Diagnostic Report
Heap snapshot öncesi daha düşük riskli diagnostic report alınabilir. Runtime, heap, stack ve resource bilgisi sağlar. Artifact persistent ve secure storage'a taşınır. Environment secret içeriği policy'ye göre excluded edilir. Report timestamp metric timeline ile eşleştirilir.
Snapshot Kararı
Heap leak güçlü ihtimalse ve replica yeterli headroom'a sahipse snapshot düşünülebilir. Process container limitine birkaç yüzde kalmışsa snapshot OOM riski taşır. Replica memory limiti geçici artırılmış forensic environment'a taşınabilir. Production data sensitivity security owner ile değerlendirilir. Birden fazla snapshot gerekiyorsa total risk hesaplanır.
Restart
Evidence toplandıktan sonra process controlled restart ile service pool'a döndürülebilir. Restart reason kaydedilir. Memory baseline başlangıçta normal olup olmadığı doğrulanır. Eğer hemen tekrar yükseliyorsa rollback düşünülebilir. Incident boyunca restart count izlenir.
Root Cause Analysis
RCA hangi reference veya resource lifecycle'ın problemi oluşturduğunu açıklamalıdır. “Node çok RAM kullandı” yeterli değildir. Leak rate, snapshot evidence ve fix test sonucu rapora eklenir. Coding standard veya monitoring eksikliği varsa process improvement belirlenir. Benzer servislerde aynı anti-pattern repository search ile kontrol edilir.
Heap Snapshot Hangi Pod'dan Alınmalıdır?
Snapshot service içindeki rastgele pod'dan değil gerçek leak pattern gösteren replica'dan alınmalıdır. Yeni restart olmuş pod değerli evidence taşımayabilir. Seçilen replica yeterli memory headroom'a sahip olmalı ve mümkünse kullanıcı trafiğinden çıkarılmalıdır. Dump tamamlandıktan sonra process restart edilebilir. Artifact güvenli ve kontrollü kanalla analysis ortamına aktarılmalıdır.
Leak Gösteren Replica
Uptime ve memory slope en yüksek pod seçilebilir. HeapUsed growth varsa JavaScript snapshot anlamlıdır. Yalnız RSS growth varsa snapshot yanında native hypothesis düşünülmelidir. Pod deployment version doğrulanır. Replica diğer pod'larla aynı traffic mix alıyor mu kontrol edilir.
Yeterli Memory Headroom
Snapshot ciddi geçici memory kullanır. Container current usage ile limit arasındaki fark yeterli değilse işlem yapılmamalıdır. Gerekirse forensic copy daha büyük memory limit ile çalıştırılır. Headroom yalnız heap değil external ve OS overhead'i de kapsar. Snapshot sırasında OOM olursa artifact kaybedilebilir.
Trafikten Çıkarılmış Replica
Readiness kapatılıp request drain tamamlanır. Snapshot event loop'u bloklasa bile kullanıcı trafiği etkilenmez. Replica HPA tarafından beklenmedik şekilde terminate edilmemelidir. Diagnostic window operasyon ekibi tarafından korunur. İşlem bittiğinde replica yeniden eklenmek yerine restart edilebilir.
Snapshot Sonrası Replica Restart
Snapshot process üzerinde ciddi stress oluşturabilir. Investigation replica'sını restart etmek temiz state sağlar. Dump file persistent storage'a taşındığı doğrulanır. Restart sonrası pod health gözlenir. Leak devam ediyorsa snapshot replica tekrar traffic'e verilmeden rollback değerlendirilebilir.
Dump Dosyasını Güvenli Transfer
Heap snapshot hassas token ve PII içerebilir. Transfer encrypted channel üzerinden yapılmalıdır. Public file sharing kullanılmamalıdır. Access yalnız RCA ekibiyle sınırlandırılır. Analysis tamamlandığında secure deletion policy uygulanır.
Memory Problemlerinde Canary Deployment
Memory fix veya Node runtime upgrade'i bütün replica'lara aynı anda dağıtılmamalıdır. Canary tek veya küçük sayıda replica ile gerçek traffic altında memory baseline ve leak rate ölçmeyi sağlar. Stable deployment ile aynı dashboard üzerinde karşılaştırma yapılır. GC ve P99 latency de memory fix'in performans yan etkisini gösterir. Rollout gate önceden tanımlanmış threshold'lara bağlanmalıdır.
Tek Replica
İlk canary bir replica ile başlayabilir. Yeterli traffic almıyorsa leak ortaya çıkmayabilir. Routing belirli düşük yüzdede request canary'ye yönlendirir. Pod memory limit stable deployment ile aynı olmalıdır. Uptime leak cycle'ı gösterecek kadar uzun tutulmalıdır.
Düşük Trafik Oranı
Canary toplam trafiğin küçük kısmını alarak blast radius'u sınırlar. Memory growth request-normalized ölçülür. Düşük traffic nedeniyle test çok uzuyorsa percentage kontrollü artırılabilir. Critical user segment canary'den hariç tutulabilir. Traffic mix normal production dağılımını temsil etmelidir.
Memory Baseline
Warm-up sonrası canary RSS ve heap baseline kaydedilir. Stable replica aynı uptime aralığında karşılaştırılır. Yeni version'ın başlangıç overhead'i ve slope ayrı değerlendirilir. Stable ama daha yüksek baseline budget içinde olabilir. Continuous growth rollout blocker'dır.
Leak Rate
MB/saat veya byte/request canary ve stable version arasında hesaplanır. Fix doğruysa candidate slope sıfıra yaklaşmalıdır. Traffic farkı normalize edilir. Confidence için yeterli request sayısı beklenir. Threshold aşılırsa rollout durur.
GC
Memory fix object lifetime'ını değiştirdiğinde GC pattern de değişebilir. Major GC frequency ve pause duration izlenir. Daha düşük heap ama çok daha yüksek allocation churn farklı performance problem yaratabilir. GC metric stable release ile karşılaştırılır. Runtime upgrade canary'sinde özellikle önemlidir.
Latency
P99 latency fix'in user-facing sonucunu gösterir. Memory düşerken latency yükseliyorsa optimization trade-off değerlendirilmelidir. Cache küçültme hit ratio'yu düşürüp database latency artırabilir. Memory ve latency SLO aynı rollout gate'te bulunmalıdır. Tek metric başarı tanımı olmamalıdır.
Rollout Gate
Gate maximum RSS, leak rate, error rate ve P99 threshold'larını içerebilir. Canary yeterli duration görmeden automatic promotion yapılmamalıdır. Breach durumunda rollout pause veya rollback edilir. Human review high-risk runtime upgrade için eklenebilir. Gate criteria repository deployment policy içinde version control altında tutulmalıdır.
Memory-Based Autoscaling Mantıklı mı?
Memory utilization autoscaling için yararlı sinyal olabilir fakat memory leak'i scale out ederek çözmek doğru değildir. Leak varsa yeni pod'lar da zamanla aynı problemi yaşar. Stateless workload request rate, CPU, queue depth ve memory gibi birden fazla sinyalle daha doğru ölçeklenebilir. Memory yüksek ama traffic düşükse scaling yerine incident investigation gerekebilir. Autoscaler architecture root cause'u gizlemeyecek şekilde tasarlanmalıdır.
Memory Leak'i Scale Out ile Gizlemek
Yeni replica traffic'i bölerek leak rate per pod'u yavaşlatabilir. Bu durum problem çözülmüş gibi görünür. Toplam cluster memory tüketimi ise artmaya devam eder. Uptime normalize leak metric bunu görünür kılar. HPA memory pressure nedeniyle sürekli scale out yapıyorsa alert oluşturulmalıdır.
Memory Utilization
Memory request'e göre utilization HPA metric olabilir. Request yanlış sizing yapılmışsa signal da yanlış olur. Cache-heavy service load düştüğünde memory hemen düşmeyebilir. Bu nedenle memory CPU gibi hızlı elastic signal değildir. Workload karakterine göre smoothing uygulanmalıdır.
Request Rate
Stateless API için request rate capacity ile daha doğrudan ilişkili olabilir. Per pod target RPS benchmark'tan çıkarılabilir. Memory leak olduğunda request rate normal kalırken RSS artar. Bu ayrım scaling ve incident kararını ayırır. Queue workload'unda request rate yerine queue depth daha anlamlı olabilir.
CPU
CPU utilization throughput pressure'ını gösterebilir. GC pressure memory leak nedeniyle CPU'yu yükselterek HPA'yı da tetikleyebilir. Bu durumda scaling kısa vadede latency'yi korusa da root cause devam eder. GC metric correlation gerekir. Multi-signal policy yanlış reaction riskini azaltır.
Queue Depth
Async worker sisteminde pending queue gerçek demand'i temsil eder. Worker scale out queue age ve depth'e göre yapılabilir. Her worker concurrency memory budget ile sınırlıdır. Queue depth yüksekken memory de yüksekse per-worker batch size fazla olabilir. Scaling policy bu iki değeri birlikte değerlendirebilir.
Çoklu Scaling Signal
CPU, request rate, queue depth ve memory bir arada daha zengin capacity görünümü sağlar. Policy aşırı hassas olmamalıdır. Memory leak detection alert'i autoscaling logic'inden ayrı tutulmalıdır. Scaling event dashboard annotation olarak memory graph'a eklenir. Capacity test policy'nin overload davranışını doğrular.
Memory-Efficient Node.js Kodlama İlkeleri
Memory-efficient kod yazmak her object'i micro optimize etmek anlamına gelmez. En büyük kazanım object lifetime'ını kısaltmak, sınırsız collection kullanmamak ve resource cleanup'ı standard hâle getirmekten gelir. Büyük veri stream veya batch ile işlenmeli, concurrency dependency kapasitesine göre sınırlandırılmalıdır. Gereksiz deep copy ve serialization azaltılmalıdır. Bu ilkeler Kurumsal Node.js Projelerinde Bellek (Memory) Yönetimi için günlük code review pratiğine dönüştüğünde incident sayısı belirgin şekilde azalır.
Büyük Objelerin Lifetime'ını Kısaltmak
Large object yalnız gerektiği scope boyunca referenced kalmalıdır. Callback bütün object yerine gerekli primitive değerleri capture edebilir. Batch işlendiğinde collection reference bırakılabilir. Global cache'e büyük payload yazılmamalıdır. Heap snapshot retained graph bu principle'in ihlal edildiği yerleri gösterir.
Unbounded Collection Kullanmamak
Her Map, Set, queue ve array için maksimum growth sorusu sorulmalıdır. “Process restart olunca temizleniyor” geçerli capacity policy değildir. TTL, maximum count veya byte limit uygulanabilir. Growth metric component seviyesinde export edilir. Code review limitsiz collection için explicit justification ister.
Cleanup Contract Oluşturmak
Timer, listener, socket ve database client acquire edildiğinde release noktası tanımlanır. `close`, `destroy` veya `dispose` gibi ortak method isimleri kullanılabilir. Cleanup idempotent olmalıdır. Error path testleri resource'un yine kapandığını doğrular. Lifecycle code tek module içinde görünür tutulmalıdır.
Stream Kullanmak
Büyük file ve dataset tek Buffer veya array olarak memory'ye alınmamalıdır. Stream backpressure producer ve consumer hızını dengeler. `pipeline()` cleanup ve error propagation sağlar. highWaterMark benchmark ile belirlenir. Client disconnect source stream'i iptal etmelidir.
Paralelliği Sınırlandırmak
Binlerce Promise aynı anda oluşturulmamalıdır. Semaphore veya worker pool active operation sayısını sınırlar. Pending queue da bounded olmalıdır. Limit downstream capacity ve memory testine göre seçilir. Timeout ve cancellation overload sırasında retained state'i azaltır.
Büyük Verileri Batch İşlemek
Database export veya migration data küçük batch'lere bölünür. Her batch persist veya send edildikten sonra memory bırakılır. Batch size throughput ve RSS dengesiyle belirlenir. Cursor dataset'in tamamını offset memory'ye almadan ilerletir. Checkpoint long-running job restart dayanıklılığı sağlar.
Gereksiz Object Copy'den Kaçınmak
Object spread veya array mapping bazen aynı data'nın birkaç kopyasını aynı anda oluşturur. Hot path'te bu allocation churn GC pressure yaratabilir. Her copy'yi kaldırmak readability'yi bozabilir. Profiler gerçekten hotspot gösteriyorsa optimization yapılmalıdır. Büyük payload transform'larında in-place veya stream mapping daha etkili olabilir.
Resource Lifecycle Standardı
Resource lifecycle standardı her kaynak için acquire, use ve release adımlarını görünür hâle getirir. Database client, timer, listener, stream, file handle ve socket aynı düşünce modeliyle yönetilebilir. Resource owner cleanup sorumluluğunu başka bir module'e bırakmamalıdır. Error ve cancellation path'leri normal success kadar test edilmelidir. Bu standard memory leak dışında connection leak ve file descriptor exhaustion gibi sorunları da azaltır.
Acquire
Resource oluşturulduğu anda owner belirlenmelidir. Connection pool client, listener veya timer handle hangi object'e aittir sorusu cevaplanır. Acquire başarısızsa partial state cleanup edilir. Metrics active resource sayısını artırabilir. Maximum concurrent acquire limitlenebilir.
Use
Resource kullanım süresi mümkün olduğunca kısa tutulmalıdır. Connection uzun CPU işi sırasında gereksiz yere açık kalmamalıdır. Stream consumer backpressure'a uymalıdır. Listener scope business operation'dan uzun olmamalıdır. Timeout resource kullanımına üst sınır getirir.
Release
Release success ve failure fark etmeksizin çalışmalıdır. `finally` bu amaç için sık kullanılan yapıdır. Cleanup idempotent olmalıdır. Release error'ı monitoring'e yazılmalı ancak original business error'ın kaybolmasına izin verilmemelidir. Active resource metric başlangıç değerine dönmelidir.
Database Client
Pool'dan alınan client query veya transaction sonunda release edilir. Early return branch'leri review edilir. Acquisition timeout uygulanır. Client global cache'de saklanmaz. Integration test pool exhaustion senaryosunu simüle eder.
Timer
Timer owner handle'ı saklar. Operation bittiğinde clear çağrısı yapılır. Shutdown bütün long-lived timer'ları temizler. Per request interval kullanımından kaçınılır. Fake timer unit test lifecycle'ı doğrular.
Listener
Listener registration ve removal aynı component içinde bulunur. Single event için once tercih edilir. Abort veya close event cleanup trigger olabilir. Anonymous callback remove işlemini zorlaştırıyorsa named reference kullanılır. Listener count test sonunda baseline'a dönmelidir.
Stream
Stream normal completion, error ve cancellation durumunda kapanmalıdır. `pipeline` birden fazla stream'i ortak lifecycle içinde yönetebilir. Source veya destination error diğer tarafı destroy etmelidir. File descriptor leak test edilmelidir. Backpressure contract korunmalıdır.
File Handle
File handle açıldıktan sonra finally veya API lifecycle ile kapanmalıdır. Çok sayıda open handle OS limitine ve memory overhead'e yol açabilir. Stream API handle cleanup'ını kolaylaştırabilir. Error path özellikle test edilmelidir. Temporary file deletion ayrı resource step olabilir.
Socket
Socket close olduğunda listener ve application state temizlenmelidir. Timeout dead connection'ları sınırlar. Outbound queue bounded olmalıdır. Shutdown yeni socket kabulünü durdurur. Active socket metric graceful drain tamamlandığında sıfıra yaklaşmalıdır.
Cleanup Contract Nedir?
Cleanup contract bir component'in başlattığı resource'ları nasıl ve ne zaman kapatacağını açık API ile tanımlar. Constructor veya `start()` acquisition yapıyorsa karşılığında `close`, `destroy` veya `dispose` benzeri method bulunur. Cleanup birden fazla kez çağrıldığında güvenli davranmalıdır. Unit test start ve cleanup sonrasında timer, listener ve connection state'ini kontrol eder. Bu yaklaşım resource ownership'i codebase genelinde anlaşılır hâle getirir.
Constructor / Start
Constructor içinde heavy resource acquisition test ve error handling'i zorlaştırabilir. Explicit `start()` lifecycle bazı component'lerde daha açık olabilir. Başlatılan her timer veya listener listelenmelidir. Partial start failure cleanup yapılmalıdır. Application bootstrap lifecycle bu API'yi kontrollü çağırır.
close()
`close()` yeni iş kabulünü durdurup mevcut kaynakları bırakmak için semantic olarak uygundur. Server, pool veya consumer component'lerinde sık kullanılır. Promise döndürerek async drain beklenebilir. Timeout sonsuz kapanmayı önler. İkinci çağrı güvenli no-op olabilir.
destroy()
`destroy()` stream veya socket gibi resource'larda daha ani termination anlamı taşıyabilir. Error object ile çağrıldığında failure downstream'e iletilebilir. Normal close ile forced destroy ayrımı API document'te belirtilmelidir. Cleanup sonunda listener'lar bırakılmalıdır. Destroy sonrası object tekrar kullanılmamalıdır.
dispose()
`dispose` general resource release semantic'i sunabilir. Modern JavaScript disposable pattern'leriyle uyumlu tasarımlar yapılabilir. Team naming standardı farklı component'lerde consistent olmalıdır. Sync veya async dispose ayrımı belirginleştirilmelidir. Resource owner dışarıdan cleanup trigger alabilmelidir.
Idempotent Cleanup
Close event ve error event aynı anda cleanup çağırabilir. Idempotent function ikinci çağrıda zarar vermez. Internal `closed` state kullanılabilir. Double release database client veya listener removal sorunları böylece önlenir. Test aynı cleanup method'unu iki kez çağırmalıdır.
Test Edilebilir Cleanup
Component start sonrası active timer veya listener count ölçülebilir. Cleanup çağrıldığında count baseline'a dönmelidir. Mock dependency release spy ile doğrulanabilir. Error path için fault injection yapılır. Test cleanup contract'ını documentation kadar güçlü hâle getirir.
Graceful Shutdown ve Memory Yönetimi
Graceful shutdown process termination sırasında yeni iş kabulünü durdurup mevcut resource'ları kontrollü biçimde serbest bırakır. Kubernetes gibi orchestration ortamlarında SIGTERM deployment ve scaling sırasında normal bir event'tir. Readiness önce kapatılmalı, ardından HTTP server ve queue consumer drain edilmelidir. Database pool ve timer'lar sona erdirilir. Belirli timeout sonunda process kapanmalı ve sonsuz pending operation beklenmemelidir.
SIGTERM
SIGTERM process'e kontrollü kapanma isteği bildirir. Application signal handler yalnız shutdown sequence'i başlatmalıdır. Aynı signal ikinci kez gelirse forced exit policy olabilir. Handler yeni resource oluşturmamalıdır. Exit reason structured log olarak kaydedilebilir.
Readiness'i Kapatmak
Shutdown başlarken readiness false yapılır. Load balancer'ın yeni traffic göndermeyi kesmesi beklenir. Propagation kısa süre alabileceği için HTTP server hemen öldürülmemelidir. Drain window service mesh davranışıyla uyumlu olmalıdır. Test deployment rollout sırasında zero dropped request hedefini doğrular.
HTTP Server Stop
Server yeni connection kabul etmeyi durdurur. Existing keep-alive connection'lar drain edilir. Maximum shutdown timeout belirlenir. Long-running request cancellation policy olmalıdır. WebSocket için ayrı close frame ve timeout gerekebilir.
Queue Consumer Stop
Consumer yeni message fetch etmeyi durdurur. Active jobs tamamlanabilir veya retry için broker'a bırakılabilir. Prefetched message sayısı memory budget'ı etkiler. Shutdown timeout sonrasında unfinished job behavior net olmalıdır. Idempotency duplicate processing riskini azaltır.
DB Pool Close
Yeni query kabul edilmediğinde pool connection'ları kapanabilir. Active transaction'ların tamamlanması için sınırlı süre verilir. Pool close promise'i await edilebilir. Shutdown sırasında yeni acquire yapan code engellenmelidir. Open handle test process'in clean exit ettiğini doğrular.
Timer Cleanup
Background interval'lar shutdown sırasında clear edilir. Timer yeni job schedule etmemelidir. Scheduled task external queue kullanıyorsa lock release gerekebilir. Cleanup function idempotent olmalıdır. Active timer count testte sıfırlanmalıdır.
Pending Request Timeout
Graceful shutdown sonsuza kadar request beklememelidir. Maximum drain deadline tanımlanır. Deadline aşan request iptal veya connection close ile sonlandırılır. Client retry için uygun status veya connection semantics tasarlanır. Shutdown timeout orchestrator termination grace period'dan kısa olmalıdır.
Kurumsal Node.js Memory Coding Standardı
Memory coding standard developer'ın her feature için sıfırdan karar vermesini önler. Bounded cache, listener cleanup, request body limiti ve concurrency limiti varsayılan kurallar hâline gelir. Büyük dosya için stream, database sonuçları için pagination veya cursor teşvik edilir. Resource cleanup ve memory monitoring code review checklist'e girer. Standard zaman içinde gerçek incident RCA bulgularıyla güncellenmelidir.
Bounded Cache Zorunluluğu
Yeni in-memory cache maximum entry veya byte limit olmadan merge edilmemelidir. TTL requirement ayrıca belirtilir. Hit, miss ve size metriği sağlanır. Cache persistent business state tutmaz. Exception gerekiyorsa architecture review ister.
Listener Cleanup Standardı
Listener registration code yanında cleanup yolu görünür olmalıdır. Single-use event için once tercih edilir. Long-lived subscription owner close method sunar. Test listener count'u doğrular. MaxListeners limitini artırmak leak çözümü olarak kabul edilmez.
Request Body Limit
Her public server JSON ve multipart body limitine sahip olmalıdır. Endpoint-specific büyük payload explicit olarak configure edilir. Upload file stream edilir. Limit aşımı metric üretir. Reverse proxy ve application limitleri uyumlu tutulur.
Concurrency Limit
Bulk job ve external API fan-out bounded concurrency kullanmalıdır. `Promise.all` yalnız input count güvenilir şekilde küçükse kullanılabilir. Semaphore veya batch limit config üzerinden ayarlanır. Pending queue maximum size alır. Dependency timeout zorunludur.
Stream Kullanımı
Büyük file ve database export stream veya batch ile işlenmelidir. `readFile` large unbounded input için kullanılmamalıdır. Backpressure korunur. Pipeline error cleanup test edilir. highWaterMark değişikliği benchmark ister.
Resource Cleanup
Connection, timer, listener, socket ve file handle lifecycle contract'a sahip olmalıdır. `finally` gereken yerlerde kullanılır. Cleanup idempotent olmalıdır. Error path test edilir. Graceful shutdown aynı cleanup API'lerini kullanır.
Memory Monitoring
Yeni service production'a çıkmadan RSS, heapUsed ve external metric export etmelidir. Container limit dashboard'da görünür olmalıdır. OOM ve restart alert'i bulunmalıdır. Cache veya queue gibi özel resource metric'leri eklenir. Soak test release checklist'e dahil edilir.
Code Review'da Memory Checklist
Memory problemi çoğu zaman code review sırasında birkaç basit soruyla yakalanabilir. Yeni collection'ın maksimum boyutu, listener'ın cleanup noktası ve query'nin maximum row sayısı sorgulanmalıdır. Büyük file veya payload'ın tamamen RAM'e alınıp alınmadığı kontrol edilir. Promise cancellation ve concurrency limiti incelenir. Checklist developer'ı yavaşlatmak yerine production incident riskini daha feature merge olmadan görünür kılar.
Bu Collection Sınırsız Büyüyebilir mi?
Map, Set, array veya queue için upper bound açıklanmalıdır. User veya request sayısıyla lineer büyüyorsa limit gerekir. TTL tek başına peak growth'u sınırlandırmayabilir. Metric size değerini izlemelidir. “Normalde az olur” production guarantee kabul edilmemelidir.
Bu Listener Nerede Kaldırılıyor?
Registration satırından cleanup path'e ulaşılabilmelidir. Once kullanımının event kesin oluşmadığında ne yaptığı düşünülür. Abort ve error path cleanup içerir. Shared emitter request listener'ı tutmamalıdır. Unit test removal spy kullanabilir.
Bu Timer Nerede Kapatılıyor?
Timer handle owner tarafından saklanmalıdır. Request veya service stop olduğunda clear edilir. Per request interval güçlü warning sign'dır. Timeout completion sonrası erken temizlenebilir. Graceful shutdown timer'ları kapatır.
Bu Promise İptal Edilebilir mi?
Remote dependency sonsuza kadar beklememelidir. Timeout tanımlıdır. API AbortSignal destekliyorsa cancellation propagation kullanılır. Pending queue bounded olmalıdır. Client disconnect gereksiz downstream işini durdurabilir.
Bu Query Kaç Satır Getirebilir?
User filter kaldırıldığında query tüm tabloyu döndürebilir mi sorusu cevaplanmalıdır. Server-side maximum pagination limit gerekir. Export stream veya cursor kullanmalıdır. `SELECT *` gereksiz field taşıyabilir. Load test realistic data volume kullanmalıdır.
Bu Dosya Tamamen RAM'e mi Alınıyor?
File maximum size küçük ve sabit değilse stream tercih edilmelidir. Upload parser memory storage kullanıyorsa limit kontrol edilir. Concurrent file count worst case memory'ye çevrilir. Transform pipeline backpressure destekler. Temporary file cleanup error path'te çalışır.
Bu Cache'in Limiti Var mı?
Maximum entry veya byte limit explicit olmalıdır. TTL ve eviction policy tanımlıdır. Key cardinality anlaşılmalıdır. Cache metric dashboard'a eklenir. Multi replica consistency gerekiyorsa external cache değerlendirilir.
Kurumsal Node.js Memory Architecture Örneği
Örnek production architecture stateless Node.js API, küçük bounded LRU cache, external Redis cache, sınırlı PostgreSQL pool ve streaming file processing kullanabilir. Uzun süre bekleyen işler external queue üzerinden worker'lara dağıtılır. Prometheus process ve application metrics toplar, Grafana RSS, heap ve GC dashboard'u sunar. Container memory limit ve V8 heap budget ayrı tanımlanır. Bu architecture memory'yi tek bir runtime flag yerine sistemin bütün katmanlarında kontrol eder.
Stateless API
Request business state process global memory'de tutulmaz. Replica restart kullanıcı state'ini kaybettirmez. Session veya durable cache external store'dadır. Horizontal scaling daha öngörülebilir olur. Process-local cache yalnız optimization olarak bounded kullanılır.
Bounded LRU Cache
Hot reference data küçük LRU cache içinde tutulabilir. Maximum entry ve TTL belirlenir. Hit, miss ve eviction metric export edilir. Large object cache dışı bırakılır. Cache restart sonrası doğal olarak yeniden warm olur.
Redis
Shared cache replica'lar arasında duplicate memory'yi azaltabilir. TTL ve maxmemory policy external sistemde ayrıca yönetilir. Node client pool veya socket sayısı bounded olmalıdır. Redis outage application memory'de sınırsız fallback queue oluşturmamalıdır. Cache miss database capacity planıyla uyumlu olmalıdır.
PostgreSQL Pool
Pool size replica sayısıyla birlikte hesaplanır. Connection acquisition timeout vardır. Query result pagination veya cursor ile sınırlandırılır. Release finally içinde yapılır. Pool wait count metric export edilir.
Streaming File Processing
Upload object storage'a stream edilir. Transform `pipeline()` üzerinden bağlanır. highWaterMark benchmark ile seçilir. File size ve concurrent upload limitlidir. Client disconnect bütün pipeline'ı iptal eder.
External Queue
Long-running jobs HTTP process heap'inde beklemez. Broker durability sağlar. Worker concurrency bounded tutulur. Message payload büyükse object storage reference kullanılır. Queue depth autoscaling ve alert sinyali olur.
Prometheus
RSS, heap, external, GC ve custom resource metrics toplanır. Label cardinality kontrollüdür. Scrape interval leak detection requirement'a uygundur. Alert rule code olarak version control altında tutulur. Retention capacity planning için yeterli tutulur.
Grafana
Dashboard pod, version ve service seviyesinde memory görünümü sunar. Container limit ve RSS aynı paneldedir. Heap, GC ve P99 latency korelasyonu görülür. Restart annotation leak reset noktalarını gösterir. Incident runbook dashboard link'i içerir.
Container Memory Limit
Her workload explicit memory request ve limit alır. Heap limit bu budget'ın yalnız bölümüdür. Native ve Buffer headroom bırakılır. Canary deployment limit değişikliklerini test eder. OOMKilled sıfıra yakın reliability hedefidir.
Uçtan Uca Memory Leak Teşhis Örneği
Bir API deployment sonrasında her pod'un RSS değeri saatte yaklaşık 40 MB artmaya başlasın. İlk incelemede heapUsed de benzer upward baseline gösteriyorsa JavaScript retention ihtimali güçlenir. Trafik ve deployment timestamp karşılaştırılır, aynı endpoint staging'de reproducible hâle getirilir ve üç snapshot alınır. Retainer tree sınırsız Map'i işaret ettiğinde fix bounded cache olarak uygulanır. Soak test ve production canary leak rate'in sıfıra yaklaştığını doğrular.
RSS Artış Alert'i
Alert container limitinin yüzde 80 üzerinde sustained RSS bildirir. Pod uptime ve version bilgisi eklenir. Grafana diğer replica'ların da aynı slope'u gösterdiğini ortaya çıkarır. Restart yeni pod'u geçici normal seviyeye getirir. Bu pattern code-level leak hipotezini güçlendirir.
heapUsed Kontrolü
HeapUsed baseline GC sonrasında sürekli artıyorsa managed heap investigation başlar. External stable kalıyorsa Buffer ihtimali azalır. Old space usage aynı slope'u gösterebilir. Heap limit henüz uzak olsa bile leak rate hesaplanır. Snapshot planı hazırlanır.
Traffic ile Korelasyon
Growth request sayısıyla lineer ise belirli endpoint candidate olabilir. Route-level request rate deployment loglarıyla karşılaştırılır. Benzersiz customer key içeren endpoint öne çıkabilir. Synthetic test aynı key pattern'i üretir. Growth tekrar oluşursa reproduction başarılıdır.
Snapshot 1
Warm-up sonrası ilk snapshot baseline olarak alınır. Cache normal startup entry'lerini içerir. Memory metric kaydedilir. Snapshot secure local storage'da tutulur. Test request henüz yoğun çalıştırılmamıştır.
Reproduce
Load generator yüz bin benzersiz key ile endpoint'i çağırır. HeapUsed artar. GC sonrası düşüş sınırlı kalır. Cache size metric aynı hızla büyür. Problem artık deterministic hâle gelmiştir.
Snapshot 2 ve 3
Her load cycle sonrası yeni snapshot alınır. Comparison Map entry ve ilgili DTO count'un sürekli arttığını gösterir. Retained size cache owner altında büyür. Üçüncü snapshot aynı pattern'i doğrular. Normal warm-up hypothesis elenir.
Retainer Tree
DTO object'leri module-level cache Map tarafından tutulur. Map application singleton üzerinden GC root'a bağlıdır. TTL veya maximum size yoktur. Root cause net biçimde tanımlanır. Fix Map'i bounded LRU cache ile değiştirir.
Leak Kaynağını Bulmak
Source search cache'e request başına unique key yazıldığını gösterir. Entry hiçbir branch'te silinmemektedir. Business requirement yalnız beş dakikalık lookup cache gerektirmektedir. TTL ve maximum count belirlenir. Cache metric ve eviction alert eklenir.
Fix
Cache LRU ve TTL ile bounded hâle getirilir. Büyük response object yerine küçük normalized value saklanır. Maximum entry benchmark üzerinden seçilir. Unit test capacity aşımında eviction doğrular. Memory regression test repository'ye eklenir.
Soak Test
Aynı 100 bin unique request birkaç cycle çalıştırılır. Cache maximum size'a ulaştıktan sonra plateau oluşturur. Heap baseline stabil kalır. P99 latency cache eviction nedeniyle kabul edilen aralıktadır. Leak rate sıfıra yaklaşır.
Production Canary
Fix tek replica'ya dağıtılır. Stable pod'larda memory artarken canary plateau gösterir. Cache hit ve database load takip edilir. SLO breach görülmez. Rollout gate geçildikten sonra deployment tamamlanır.
Uçtan Uca Örnek: Unbounded Cache Leak
Unbounded cache örneği memory leak kavramını en açık biçimde gösterir. Module-level Map her user query sonucunu kalıcı olarak tutar. Benzersiz key sayısı production traffic ile sürekli arttığı için heapUsed baseline da yükselir. Heap snapshot Map'in büyük retained graph'ını gösterir. LRU, TTL ve metrics eklendiğinde memory predictable bir üst sınır kazanır.
Problemli Map
Basit `const cache = new Map()` başlangıçta zararsız görünür. Her request `cache.set(userId, result)` çalıştırır. User cardinality milyonlara çıktığında Map hiç küçülmez. Process restart tek cleanup mekanizmasıdır. Code review bu structure için size policy istemelidir.
const cache = new Map();
export function remember(key, value) {
cache.set(key, value);
}
Memory Growth
Her unique key birkaç kilobyte object graph ekler. HeapUsed request sayısıyla yaklaşık lineer büyür. GC nesneleri silemez çünkü Map reference'ı sürer. Major GC daha sık çalışmaya başlar. Sonunda heap limit veya container limit risk oluşturur.
Heap Snapshot
Snapshot Summary Map ve cached DTO count artışını gösterir. Comparison iki load cycle arasında büyük positive delta verir. Retainers cache Map'i owner olarak gösterir. Object creation call site source code ile eşleştirilir. Leak kanıtı tamamlanır.
Retained Size
Map object'in shallow size değeri görece küçük olabilir. Retained size ise bütün cached graph nedeniyle çok büyüktür. Bu fark leak analysis'in neden yalnız object size'a bakmaması gerektiğini gösterir. Entry içinde büyük nested payload varsa impact daha da artar. Cache value normalize edilerek ikinci optimization yapılabilir.
LRU + TTL
Bounded LRU maximum entry sayısı belirler. TTL eski data'nın belirli sürede expire olmasını sağlar. İki mekanizma birlikte peak ve stale data riskini sınırlar. Maximum entry memory benchmark'tan çıkarılır. Cache stampede riskine karşı expiration jitter düşünülebilir.
Cache Metrics
Size, hit, miss ve eviction metrics export edilir. Capacity yüzdesi alert threshold alabilir. Yüksek eviction cache'in yetersiz veya key strategy'nin yanlış olduğunu gösterebilir. Hit ratio database impact ile birlikte izlenir. Memory metric cache size ile korelasyonunu korur.
Regression Test
Test cache capacity'den çok daha fazla unique key üretir. Final cache size maksimum değeri geçmemelidir. Soak boyunca heap baseline bounded kalmalıdır. TTL fake timer ile test edilebilir. Pipeline future code change'in tekrar unbounded cache oluşturmasını engeller.
Uçtan Uca Örnek: Stream Backpressure Problemi
İkinci örnekte hızlı file reader veriyi yavaş remote destination'a yazmaktadır. Kod `write()` return value'sunu yok saydığı için internal buffer sürekli büyür. Heap leak olmamasına rağmen RSS hızla yükselir. `drain` sinyali veya `pipeline()` kullanıldığında producer consumer hızına uyum sağlar. Aynı workload altında peak RSS ciddi ölçüde daha bounded hâle gelir.
Hızlı Producer
Local SSD saniyede yüzlerce megabyte veri okuyabilir. Remote client ise yalnız birkaç megabyte tüketebilir. Producer bu farkı dikkate almazsa data memory'de bekler. Stream buffer application queue'suna dönüşür. Throughput destination capacity tarafından zaten sınırlıdır.
Yavaş Consumer
Consumer network, disk veya external API nedeniyle yavaş olabilir. Temporary slowdown küçük buffer ile absorbe edilir. Sürekli yavaşlıkta producer mutlaka pause olmalıdır. Slow consumer count metric olarak izlenebilir. Timeout sonsuz connection'ı engeller.
Internal Buffer Growth
`write()` false sonrasında yazmaya devam etmek writable buffer'ı büyütür. Chunk'lar delivery beklerken memory'de kalır. Concurrent stream sayısı problemi çarpar. RSS ve writableLength birlikte artabilir. Bu pattern heap leak ile karıştırılmamalıdır.
RSS Artışı
Buffer ağırlıklı queue RSS ve external memory'yi yükseltebilir. HeapUsed daha sınırlı değişebilir. Bu metric pattern backpressure investigation'a yönlendirir. Consumer hızlandığında buffer boşalabilir. Leak'ten farklı olarak workload durduğunda memory baseline daha kolay stabil olabilir.
write() False
False return producer'a buffer pressure olduğunu bildirir. Yeni chunk üretimi durdurulmalıdır. Bu signal optional performance hint gibi görülmemelidir. Ignoring it production memory riskidir. Manual producer test yavaş writable kullanarak davranışı doğrulayabilir.
'drain'
Writable yeterli data gönderdiğinde `drain` event'i üretir. Producer bu event sonrasında devam eder. `once` listener bir cycle için temiz kullanım sağlar. Error veya close olursa waiting continuation iptal edilmelidir. Backpressure state metric debug için eklenebilir.
pipeline()
`pipeline()` source ve destination'ı backpressure-aware biçimde bağlar. Error olduğunda stream cleanup'ını kolaylaştırır. Promise API async code içinde rahat kullanılır. Custom transform'lar da zincire eklenebilir. Manual `data` event ve uncontrolled `write` pattern'inden daha güvenli default'tur.
Sonuçları Karşılaştırmak
Eski ve yeni implementation aynı file size ve destination throttle ile test edilir. Throughput destination limitine yakın kalırken peak RSS düşer. External memory daha stabil pattern gösterir. P99 event loop lag da iyileşebilir. Bu sonuç backpressure fix'inin yalnız code correctness değil capacity etkisini de kanıtlar.
Node.js Memory Yönetiminde Sık Yapılan Hatalar
Memory incident'larının önemli kısmı birkaç tekrar eden yanlış yaklaşımdan doğar. Leak görüldüğünde yalnız heap limitini artırmak, sadece RSS veya sadece heapUsed izlemek ve MaxListenersWarning'i susturmak en yaygın örneklerdir. Büyük dosyayı tek Buffer'a almak ve sınırsız `Promise.all()` kullanmak transient OOM riskini artırır. Production'da kontrolsüz heap snapshot almak incident'ı daha kötü hâle getirebilir. Restart ise kalıcı çözüm yerine yalnız temporary recovery mekanizması olarak görülmelidir.
Heap Limitini Artırarak Leak'i Çözmeye Çalışmak
Daha büyük heap leak rate'i değiştirmez. OOM yalnız daha geç gerçekleşir. Major GC daha büyük live set ile çalışabilir. Container headroom azalabilir. Önce retaining path ve lifecycle fix edilmelidir.
Yalnızca RSS İzlemek
RSS toplam footprint'i gösterir ancak source component'i ayırmaz. Heap leak, Buffer veya fragmentation aynı RSS artışını üretebilir. HeapUsed ve external metrikleri olmazsa wrong tool seçilebilir. Container limit için RSS önemini korur. Root cause için breakdown gerekir.
Yalnızca heapUsed İzlemek
Buffer-heavy service heapUsed normal görünürken kernel OOM yaşayabilir. Native addon leak'i de kaçabilir. External, arrayBuffers ve RSS birlikte izlenmelidir. Container working set ek context verir. Memory budget toplam process footprint üzerine kurulmalıdır.
MaxListenersWarning'i Susturmak
Listener limitini 10'dan 1000'e çıkarmak cleanup bug'ını çözmez. Warning kaybolur ama memory growth sürer. Önce listener lifecycle araştırılmalıdır. Legitimate high-listener architecture varsa limit measurement sonrası artırılabilir. listenerCount metric davranışı doğrular.
Sınırsız Cache Kullanmak
Cache'e maximum size koymamak traffic'i RAM allocation policy'ye dönüştürür. TTL peak growth'u tek başına engellemeyebilir. LRU veya byte limit gerekir. Cache metric capacity'yi gösterir. Shared büyük cache external store'a taşınabilir.
Büyük Dosyaları Tamamen RAM'e Almak
`readFile` veya memory upload storage küçük file için uygundur. Dosya boyutu user-controlled ise ciddi risk oluşturur. Stream processing peak memory'yi sınırlar. Concurrent upload limitlenir. Backpressure destination hızına uyar.
Promise.all() ile Kontrolsüz Paralellik
Binlerce Promise aynı anda socket, query ve result state tutar. Downstream zaten sınırlı capacity'ye sahiptir. Concurrency limiter memory ve dependency'yi korur. Batch size benchmark ile belirlenir. Pending queue da bounded olmalıdır.
Stream Backpressure'ı Yok Saymak
`write()` false sonucunu yok saymak internal buffer growth oluşturur. HighWaterMark hard memory limit değildir. Pipeline backpressure'ı doğal yönetir. Slow consumer testleri gerekli behavior'ı doğrular. RSS ve external metric impact'i gösterir.
Production'da Kontrolsüz Heap Snapshot Almak
Snapshot event loop'u bloklar ve ciddi ek memory ister. Limit yakınındaki process OOM olabilir. Replica önce drain edilmelidir. Yeterli headroom yoksa staging reproduction tercih edilir. Artifact sensitive data olarak korunmalıdır.
Memory Leak'i Restart ile Gizlemek
Restart graph'ı sıfırlar ama bug devam eder. Uptime kısa olduğunda monitoring leak slope'u göremeyebilir. Restart annotation ve rate izlenmelidir. Emergency recycling kabul edilebilir geçici control'dür. Permanent fix soak test ile doğrulanmalıdır.
Production Öncesi Node.js Memory Kontrol Listesi
Production readiness yalnız unit test ve HTTP health check ile tamamlanmamalıdır. Runtime LTS durumu, container memory budget, V8 heap limiti ve native headroom doğrulanmalıdır. Cache, request body ve concurrency limitleri açıkça tanımlanmalıdır. Memory metrics, OOM alert, soak test ve incident runbook hazır olmalıdır. Bu checklist release sırasında memory risklerini sistematik biçimde görünür kılar.
Node.js LTS Sürümü Kullanılıyor mu?
Production runtime desteklenen LTS hattında olmalıdır. EOL version security ve ecosystem riski taşır. Container base image düzenli update edilir. Dependency compatibility test edilir. Runtime upgrade policy takvimde önceden planlanır.
Container Memory Budget Tanımlı mı?
Her workload memory request ve limit değerine sahip olmalıdır. Limit historical average değil peak benchmark üzerinden belirlenir. Heap, native ve Buffer payları belgelenir. Safety margin açıkça tanımlanır. Dashboard actual usage ile budget'ı karşılaştırır.
V8 Heap Limiti Biliniyor mu?
Startup'ta `v8.getHeapStatistics()` ile actual heap size limit kaydedilir. Runtime flag ile eşleştiği doğrulanır. Container limitten yeterince düşük olmalıdır. Worker thread varsa isolate limits ayrıca değerlendirilir. Upgrade sonrası değer tekrar kontrol edilir.
Native Memory İçin Headroom Var mı?
Container memory'nin tamamı V8 heap'e ayrılmamalıdır. TLS, driver, code ve native addon memory kullanır. Buffer-heavy workload daha büyük headroom isteyebilir. Peak RSS load testte ölçülür. Snapshot operation için ayrıca forensic plan bulunur.
Cache'ler Bounded mı?
Her cache maximum count veya byte limit alır. TTL ve eviction policy tanımlıdır. Size metric monitoring'e gönderilir. Key cardinality anlaşılmıştır. Persistent state cache içine gömülmemiştir.
Request Body Limitleri Var mı?
JSON, form ve multipart ayrı limitlere sahip olabilir. Public endpoint user-controlled unlimited body kabul etmez. Large upload stream edilir. Reverse proxy limitleri application ile uyumludur. Rejected body metric izlenir.
Büyük Dosyalar Stream Ediliyor mu?
Large file tek Buffer olarak RAM'e alınmaz. Pipeline backpressure kullanır. Chunk size benchmark edilmiştir. Client disconnect cleanup çalıştırır. Concurrent transfer limitlidir.
Concurrency Limitleri Var mı?
External API fan-out ve bulk processing bounded concurrency kullanır. Queue depth sınırlıdır. Database pool capacity ile uyumludur. Timeout ve cancellation vardır. Load shedding policy tanımlıdır.
Listener Cleanup Test Ediliyor mu?
Critical EventEmitter start ve stop sonrası listener count test edilir. Once uygun yerlerde kullanılır. Error ve abort path cleanup içerir. MaxListeners warning CI loglarında fail veya review trigger olabilir. Listener limit keyfi artırılmaz.
Timer Cleanup Test Ediliyor mu?
Per request timer lifecycle unit test edilir. Interval service close sırasında temizlenir. Timeout completion sonrası clear edilir. Fake timer tooling kullanılabilir. Process graceful shutdown'da açık timer bırakmaz.
Memory Metrics Toplanıyor mu?
RSS, heapUsed, heapTotal ve external dashboard'da görünür olmalıdır. ArrayBuffers Buffer-heavy servislerde eklenir. GC ve event loop metrics impact'i gösterir. Pod version filtrelenebilir. Metric unit standardı tutarlıdır.
OOM Alert'i Var mı?
Container OOMKilled ve V8 OOM log pattern izlenir. Alert deployment context içerir. Restart count ile correlate edilir. On-call runbook link'i bulunur. Tek OOM otomatik “recovered” sayılmaz.
Soak Test Yapıldı mı?
Application production benzeri RPS ile yeterli süre çalıştırılır. Heap baseline ve RSS slope ölçülür. Listener ve connection count izlenir. Cache warm-up test dışında ayrıştırılır. Regression varsa release durdurulur.
Memory Regression Testi Var mı?
Baseline ve candidate aynı load altında karşılaştırılır. Allowed growth threshold tarihsel variance üzerinden belirlenir. Peak ve final baseline ayrı ölçülür. Pipeline failure diagnostic artifact sunar. Node runtime upgrade aynı testten geçer.
Incident Runbook Hazır mı?
Alert sonrası hangi pod'un drain edileceği tanımlıdır. Diagnostic report ve snapshot karar kriterleri yazılıdır. Artifact security prosedürü bulunur. Restart ve rollback adımları test edilmiştir. RCA owner ve post-incident action süreci bellidir.
Node.js için En İyi Programlama Dili Hangisidir?
Node.js doğrudan JavaScript runtime'ıdır ve TypeScript de build aşamasında JavaScript'e dönüştürülerek yaygın biçimde kullanılır. Memory davranışının temelini ise dil seçimi değil V8 object lifetime, asynchronous resource yönetimi ve workload architecture belirler. TypeScript type safety ile resource API'lerini daha açık hâle getirebilir. Ancak bounded cache veya listener cleanup gibi kurallar type system tarafından otomatik garanti edilmez. Backend teknoloji seçimi ekip yetkinliği, latency hedefi ve operasyon gereksinimiyle birlikte değerlendirilmelidir.
JavaScript
JavaScript Node.js'in native development dilidir. Build step olmadan hızlı development sağlar. WeakMap, streams, AsyncLocalStorage ve Worker Threads doğrudan kullanılabilir. Runtime type hataları test ve validation ile kontrol edilmelidir. Memory leak davranışı TypeScript'ten farklı değildir çünkü ikisi de sonuçta V8 üzerinde JavaScript çalıştırır.
TypeScript
TypeScript compile-time type safety sağlar. Resource interface içinde `close()` veya cache config contract açıkça tanımlanabilir. IDE refactor büyük backend codebase'inde avantaj sunar. Runtime input validation yine ayrıca gerekir. Memory budget ve cleanup davranışı architecture testleriyle korunmalıdır.
Kurumsal Node.js Projelerinde TypeScript Avantajları
Typed DTO, config ve service interface code review'u kolaylaştırır. Bounded cache wrapper generic API ile güvenli kullanılabilir. Optional cleanup method yerine zorunlu lifecycle interface tanımlanabilir. Worker message schema type ile netleştirilebilir. Yine de compile-time güvenlik resource leak'i tek başına engellemez.
Node.js ile Go / Java / C# Karşılaştırması
Her runtime'ın garbage collector, concurrency ve memory modeli farklıdır. Node.js event-driven I/O workload'larında güçlü developer productivity sunar. Go, Java ve C# farklı threading ve GC tuning seçenekleri taşır. Teknoloji seçimi yalnız benchmark chart üzerinden yapılmamalıdır. Ekip operasyon bilgisi ve gerçek workload prototipi karar için daha değerlidir.
Programlama Dilinden Daha Önemli Olan Runtime ve Sistem Bilgisi
Developer event loop, streams, GC, Linux process memory ve container limitlerini anlamalıdır. Aynı TypeScript kodu kötü resource lifecycle ile production leak oluşturabilir. Database pagination ve backpressure bilgisi memory davranışını doğrudan etkiler. Observability olmadan runtime problem görünmez kalır. Bu nedenle sistem bilgisi dil syntax'ından daha belirleyicidir.
Yazılımcı Olmak İçin Ne Yapmalı? Node.js Backend Yol Haritası
Node.js backend geliştirme öğrenirken yalnız framework endpoint yazmak yeterli değildir. JavaScript ve TypeScript temeli üzerine event loop, asynchronous programming ve streams bilgisi eklenmelidir. V8 ve garbage collection memory davranışını anlamayı sağlar. SQL, Docker, observability ve profiling production yetkinliğini tamamlar. Gerçek production benzeri proje geliştirmek bütün bu parçaların birlikte nasıl çalıştığını görmenin en iyi yollarından biridir.
JavaScript
Scope, closure, prototype ve Promise temelleri iyi öğrenilmelidir. Memory leak'lerin önemli bölümü reference lifecycle ile ilişkilidir. EventEmitter ve streams core API olarak çalışılmalıdır. Error handling ve async iteration pratik edilmelidir. Küçük framework'süz Node server underlying runtime'ı anlamayı kolaylaştırır.
TypeScript
Generic, interface ve strict null checks backend code kalitesini artırır. DTO ve domain model ayrımı öğrenilmelidir. Worker message ve event payload type'ları tanımlanabilir. Runtime validation ile compile-time type farkı anlaşılmalıdır. Büyük open-source TypeScript Node projeleri okunabilir.
Event Loop
Timers, I/O callbacks ve microtask davranışı öğrenilmelidir. Synchronous CPU işinin request latency'yi neden blokladığı görülmelidir. GC pause event loop etkisiyle ilişkilendirilmelidir. Event loop lag metric uygulamalı ölçülmelidir. Worker Threads'in ne zaman gerektiği anlaşılmalıdır.
Async Programming
Promise, async/await, cancellation ve timeout temel konulardır. `Promise.all` concurrency anlamı uygulamalı görülmelidir. Semaphore ve queue pattern'i yazılmalıdır. Error propagation ve cleanup finally ile pratik edilmelidir. Pending Promise memory testleri yapılabilir.
Streams
Readable, Writable ve Transform stream öğrenilmelidir. Backpressure `write()` ve `drain` üzerinden gözlenmelidir. `pipeline()` ile file copy yapılabilir. highWaterMark farklı değerlerle benchmark edilir. Büyük file `readFile` ve stream yaklaşımı memory açısından karşılaştırılabilir.
V8 ve Garbage Collection
Young ve old generation temel modeli öğrenilmelidir. `process.memoryUsage()` ile heap ve RSS ayrımı görülmelidir. Heap snapshot leak lab yapılabilir. GC logs ve allocation profiler incelenebilir. Runtime tuning ancak bu temel oturduktan sonra denenmelidir.
SQL ve Database
Pagination, index ve query plan backend memory ile doğrudan ilişkilidir. Büyük result set'in heap üzerindeki etkisi ölçülmelidir. Pool sizing öğrenilmelidir. Transaction ve connection release pratik edilmelidir. Cursor ve row stream kullanılmalıdır.
Docker
Container memory limit ve OOM davranışı test edilmelidir. Node heap limit ile container limit farkı gözlenmelidir. Image LTS runtime kullanmalıdır. SIGTERM graceful shutdown uygulanmalıdır. Local stress test cgroup altında çalıştırılabilir.
Observability
Prometheus metric, structured log ve trace farkları öğrenilmelidir. RSS ve heap Grafana dashboard'u kurulabilir. Alert growth rate üzerinden yazılabilir. High-cardinality label problemi deneyle görülebilir. Incident runbook oluşturulmalıdır.
Performance Profiling
CPU flame graph, heap snapshot ve allocation profile farklı sorulara cevap verir. Hangi durumda hangi araç kullanılacağı öğrenilmelidir. Staging benchmark repeatable tutulmalıdır. Profiling overhead ölçülmelidir. Fix sonrası aynı profile tekrar alınmalıdır.
Gerçek Production Benzeri Proje Geliştirmek
Proje database, cache, queue ve observability içermelidir. Container memory limit altında load test yapılmalıdır. Intentional leak eklenip teşhis edilebilir. Canary deployment ve rollback simüle edilir. Bu pratik iş görüşmesinde framework CRUD örneğinden çok daha güçlü teknik deneyim kazandırır.
Open Source ve İşbirliği ile Node.js Memory Yetkinliği
Open-source projelerde gerçek memory bug report'larını incelemek production problem çözme becerisini geliştirir. Node.js core, V8, profiling tool'ları ve cache library'leri farklı seviyelerde memory management örnekleri sunar. Minimal reproduction hazırlamak sorunu framework gürültüsünden ayırmayı öğretir. Pull request ve benchmark paylaşımı teknik iletişim pratiği sağlar. Küçük contribution bile runtime bilgisini günlük application geliştirmesinden daha hızlı geliştirebilir.
Node.js Core
Node.js issue tracker memory, stream ve diagnostics edge case'leriyle doludur. Release notes runtime davranış değişikliklerini gösterir. Core source okumak public API'nin altında neler olduğunu anlamaya yardımcı olur. Internal API production dependency'si yapılmamalıdır. Documentation contribution iyi başlangıç olabilir.
V8
V8 garbage collection ve JavaScript optimization mekanizmalarının temel kaynağıdır. Deep runtime araştırması yapan developer design docs ve blog yazılarını inceleyebilir. Node.js belirli V8 version embed ettiği için behavior version'a bağlıdır. Application tuning current runtime üzerinden test edilmelidir. V8 flag'leri körlemesine production'a taşınmamalıdır.
Clinic.js
Clinic.js profiling workflow öğrenmek için yararlıdır. Demo application intentional memory ve CPU problemiyle test edilebilir. Tool artifact'ları ekip içinde birlikte analiz edilebilir. Version compatibility kullanılan Node sürümüyle kontrol edilmelidir. Open issue'lar gerçek profiling edge case'lerini gösterir.
lru-cache
Bounded cache implementation okumak eviction ve TTL gibi kavramları somutlaştırır. Library kullanılsa bile configuration'ın memory budget'a göre yapılması gerekir. Default davranış production requirement yerine geçmez. Benchmark kendi value size distribution'ınızla yapılmalıdır. Package update memory regression testten geçmelidir.
prom-client
Node.js application metric instrumentation örnekleri için açık kaynak Prometheus client'ları incelenebilir. Process metrics ve custom histogram kullanımı öğrenilebilir. Label cardinality design application sorumluluğudur. Metric collector'ın kendi overhead'i benchmark edilebilir. Registry lifecycle test environment'ta duplicate metric riskine karşı yönetilmelidir.
Open Source Issue İncelemek
Closed memory leak issue'ları root cause ve fix pattern'lerini gösterir. Maintainer hangi diagnostic evidence'i istediğini görmek öğreticidir. Snapshot yerine minimal reproduction'ın neden değerli olduğu anlaşılır. Version matrix oluşturma pratiği kazanılır. Aynı issue pattern kendi codebase'inizde aranabilir.
Minimal Reproduction Hazırlamak
Problem birkaç dosyalık projeye indirilir. External dependency sayısı azaltılır. Load script ve memory output birlikte verilir. Sensitive data kullanılmaz. Reproduction root cause'u anlamayı çoğu zaman issue açmadan önce bile sağlar.
Pull Request
Leak fix küçük ve testli commit olarak hazırlanabilir. Regression test önce failure gösterir. Benchmark fix'in memory ve performance sonucunu belgeler. Maintainer review alternatif yaklaşım sunabilir. Merge edilmese bile öğrenme süreci değerlidir.
Performance Benchmark Paylaşmak
Benchmark workload, Node version ve hardware bilgisiyle birlikte paylaşılmalıdır. Sadece “yüzde 30 daha hızlı” ifadesi yeterli değildir. Memory, latency ve throughput birlikte verilir. Reproduction script açık olmalıdır. Başkaları sonucu tekrar edebildiğinde teknik değer artar.
Diyarbakır Yazılım Topluluğu ile Node.js Performans Çalışmaları
Node.js memory konusu topluluk içinde workshop ve ortak proje için oldukça uygundur çünkü teori doğrudan ölçülebilir sonuçlara dönüşür. Heap snapshot laboratuvarı, streaming benchmark veya container memory monitoring projesi geliştiricilerin production davranışını uygulamalı görmesini sağlar. Diyarbakır Yazılım Topluluğu hakkında daha fazla bilgi için https://www.diyarbakiryazilim.com.tr/about adresi incelenebilir. Mevcut topluluk projelerine https://www.diyarbakiryazilim.com.tr/projects üzerinden ulaşılabilir. Ortak çalışmaların benchmark script'i ve incident runbook gibi tekrar kullanılabilir çıktılar üretmesi teknik öğrenmeyi daha kalıcı hâle getirir.
Diyarbakır Yazılım Topluluğu İçinde Backend Çalışmaları
Backend çalışma grubu küçük bir Node.js servis üzerinde memory budget oluşturabilir. Cache, queue ve database pool adım adım eklenerek RSS değişimi ölçülür. Katılımcılar farklı root cause'ları birlikte analiz eder. Sonuçlar dokümantasyon ve benchmark olarak projeye eklenir. Böylece framework kullanımından production sistem düşüncesine geçiş yapılır.
Node.js Memory Workshopları
Workshop ilk bölümde process.memoryUsage ve V8 heap modelini anlatabilir. İkinci bölüm intentional leak oluşturup snapshot comparison yapabilir. Üçüncü bölüm container OOM ve graceful shutdown testine ayrılabilir. Her katılımcı aynı reproduction üzerinde farklı profiler kullanabilir. Workshop sonunda kısa incident raporu hazırlanabilir.
Heap Snapshot Laboratuvarı
Lab yalnız local veya staging synthetic data kullanmalıdır. Unbounded Map leak kontrollü olarak oluşturulur. Üç snapshot tekniği uygulanır. Retaining path bulunup fix yapılır. Snapshot security konusu teknik egzersizin parçası hâline getirilir.
Load ve Soak Test Atölyeleri
Katılımcılar kısa benchmark ile soak test farkını gözlemleyebilir. Request rate sabit tutulur. Memory growth MB/1000 request olarak hesaplanır. Baseline ve candidate build karşılaştırılır. Sonuç Grafana dashboard üzerinde yorumlanır.
Open Source ve İşbirliği Çalışmaları
Topluluk küçük Node memory tooling issue'larına contribution yapabilir. Minimal reproduction hazırlama session düzenlenebilir. Pull request review birlikte yapılabilir. Benchmark methodology ortak template hâline getirilebilir. Bu süreç teknik İngilizce ve açık kaynak iletişim becerisini de geliştirir.
Diyarbakır'daki En İyi Yazılımcılarla Teknik Deneyim Paylaşımı
Teknik deneyim paylaşımında isim veya unvan sıralamasından çok doğrulanabilir problem çözme süreçlerine odaklanmak daha faydalıdır. Bir memory incident'ın metric, snapshot ve fix adımlarını anlatmak gerçek öğrenme sağlar. Farklı geliştiriciler aynı graph üzerinde alternatif yorum sunabilir. Production tecrübeleri anonymized biçimde paylaşılabilir. Bu yaklaşım yerel geliştirici ağında tekrar kullanılabilir teknik bilgi oluşturur.
Ortak Proje Fikirleri
Ortak projeler küçük başlayıp ölçülebilir teknik hedef taşımalıdır. Her proje memory metric, benchmark ve regression test içerebilir. Repository README yalnız kurulumu değil memory architecture kararlarını da açıklamalıdır. Issue board yeni katılımcılar için küçük görevler sunabilir. Sonuçlar topluluk projeleri altında paylaşılabilir.
Memory Leak Lab
Lab uygulaması birkaç farklı leak türünü feature flag ile etkinleştirebilir. Map cache, EventEmitter ve timer leak ayrı endpoint'lerde bulunabilir. Katılımcı metric üzerinden hangi leak'in aktif olduğunu belirler. Snapshot ile retaining path bulunur. Fix regression test ile doğrulanır.
WebSocket Memory Benchmark
Proje binlerce idle ve active connection oluşturabilir. Connection başına RSS farkı ölçülür. Slow consumer outbound queue senaryosu simüle edilir. Heartbeat ve cleanup sonrası memory karşılaştırılır. Sonuç maximum connection capacity planına dönüştürülür.
Streaming API Projesi
Aynı büyük file endpoint'i önce `readFile`, sonra stream yaklaşımıyla uygulanabilir. Peak RSS ve throughput karşılaştırılır. Slow client throttle edilerek backpressure davranışı görülür. highWaterMark birkaç değerle test edilir. Pipeline error cleanup ayrıca doğrulanır.
Container Memory Monitoring Projesi
Node API Docker veya Kubernetes memory limiti altında çalıştırılır. Prometheus RSS ve heap metric toplar. Grafana container limit headroom paneli gösterir. Controlled memory growth OOMKilled event'ine kadar gözlenebilir. Runbook alert sonrası doğru investigation adımlarını uygular.
Sık Sorulan Sorular
Node.js memory management konusunda en sık sorulan sorular heap limiti, RSS farkı, snapshot güvenliği ve container OOM davranışı etrafında toplanır. Tek bir metric veya runtime flag çoğu sorunu tek başına çözmez. JavaScript heap, native memory ve Buffer alanları ayrı düşünülmelidir. Production sisteminde monitoring ve resource lifecycle code kadar önemlidir. Aşağıdaki cevaplar günlük backend geliştirmede hızlı referans olarak kullanılabilir.
Node.js memory management nasıl çalışır?
Node.js JavaScript object'lerini büyük ölçüde V8 heap üzerinde yönetir. Garbage collector artık reachable olmayan object'leri otomatik temizler. Buffer ve native allocation'lar heap dışı memory kullanabilir. Process RSS toplam footprint için daha geniş sinyal sağlar. Sağlıklı architecture heap, external ve container limitini birlikte izler.
Node.js memory leak nedir?
Memory leak ihtiyaç kalmayan verinin hâlâ reachable reference nedeniyle memory'de kalmasıdır. Global Map, listener veya timer sık nedenlerdir. GC reachable object'i silemez. Heap snapshot retaining path root cause'u gösterir. Fix reference lifecycle'ını düzeltmelidir.
Node.js neden çok RAM kullanır?
Yüksek RAM her zaman leak değildir. V8 heap, Buffer, native library, code ve allocator davranışı RSS'e katkıda bulunur. Warm-up ve cache normal memory growth yaratabilir. HeapUsed ve external breakdown incelenmelidir. GC sonrası stable baseline varsa kullanım normal workload sonucu olabilir.
RSS ile heapUsed arasındaki fark nedir?
HeapUsed yalnız V8 managed heap kullanımını gösterir. RSS process'in resident memory footprint'ini daha geniş biçimde kapsar. Buffer ve native memory RSS'i artırabilir. Heap stable iken RSS growth bu nedenle mümkündür. Linux allocator fragmentation da ayrıca değerlendirilmelidir.
Node.js heap limiti ne kadardır?
Heap limiti Node.js ve V8 sürümü, architecture ve runtime koşullarına göre değişebilir. Sabit internetteki eski bir sayıya güvenilmemelidir. `v8.getHeapStatistics().heap_size_limit` kullanılan process üzerinde gerçek değeri gösterir. Container limiti bundan ayrı bir sınırdır. Production budget actual runtime değeri üzerinden yapılmalıdır.
--max-old-space-size nedir?
Bu flag V8 old memory section maximum boyutunu MiB cinsinden ayarlar. Toplam process RSS limiti değildir. Buffer ve native memory ayrıca tüketilir. Çok düşük değer sık GC oluşturabilir. Çok yüksek değer container headroom'u azaltabilir.
--max-old-space-size-percentage ne işe yarar?
Flag V8 old space limitini available system memory'nin yüzdesine göre belirler. Aynı anda sabit old space flag verilirse percentage seçeneği öncelikli olabilir. Dinamik memory class'larında useful olabilir. Yüzde 100 güvenli değildir çünkü heap dışı memory gerekir. Runtime ve container behavior test edilmelidir.
Heap limitini artırmak memory leak'i çözer mi?
Hayır, leak reference growth devam ettiği sürece yeni limit de sonunda dolar. Sadece failure daha geç gerçekleşir. Daha büyük heap GC behavior'ını da değiştirir. Leak retaining path üzerinden düzeltilmelidir. Heap tuning fix'ten sonra capacity optimization olarak yapılabilir.
Node.js memory leak nasıl tespit edilir?
Önce RSS ve heap baseline trend'i production metrics ile doğrulanır. Reproducible load staging'de oluşturulur. Üç snapshot comparison veya allocation profile kullanılır. Retaining path root cause'u gösterir. Fix sonrası aynı soak test tekrar edilir.
Heap snapshot nasıl alınır?
Chrome Inspector, `v8.writeHeapSnapshot()`, `v8.getHeapSnapshot()` veya uygun signal seçenekleri kullanılabilir. Snapshot yalnız current V8 isolate'ı temsil eder. Worker için ayrı snapshot gerekebilir. Production replica önce drain edilmelidir. Artifact güvenli saklanmalıdır.
Heap snapshot production'da güvenli midir?
Kontrolsüz kullanım güvenli değildir. Snapshot event loop'u bloklayabilir ve önemli ek memory gerektirir. Limit yakınındaki process OOM olabilir. Ayrıca token ve PII gibi sensitive data içerebilir. Trafikten çıkarılmış yeterli headroom'a sahip replica tercih edilmelidir.
EventEmitter memory leak nasıl çözülür?
Listener'ın hangi lifecycle sonunda kaldırılması gerektiği belirlenir. Single event için `once()` kullanılabilir. Uzun subscription `off()` veya cleanup function ile kaldırılır. Error ve close path test edilir. MaxListeners limitini artırmak tek başına çözüm değildir.
MaxListenersExceededWarning ne demektir?
Node.js bir EventEmitter event'inde yüksek listener sayısı gördüğünde olası memory leak konusunda uyarı verir. Default limit 10 listener'dır ve hard limit değildir. Application daha fazla listener çalıştırmaya devam edebilir. Warning'in stack trace'i `--trace-warnings` ile görülebilir. Önce listener growth nedeni araştırılmalıdır.
Buffer memory leak nasıl tespit edilir?
HeapUsed stable iken external, arrayBuffers ve RSS artışı Buffer problemine işaret edebilir. Snapshot Buffer wrapper retaining path'ini gösterebilir. Underlying native bytes full görünmeyebilir. Binary workload load test ile reproduce edilir. Stream ve cleanup fix sonrası external baseline karşılaştırılır.
Stream backpressure nedir?
Producer consumer'dan hızlı olduğunda veri memory'de sınırsız birikmesin diye uygulanan flow control'dür. Writable `write()` false döndürürse producer durmalıdır. `drain` event'i devam sinyalidir. `pipeline()` bu davranışı kolaylaştırır. Backpressure'a uymamak yüksek RSS ve process abort riskine kadar ilerleyebilir.
Node.js Docker içinde neden OOM olur?
Container memory limit toplam process footprint'i sınırlar. V8 heap limitine ulaşılmadan Buffer veya native memory nedeniyle cgroup limiti aşılabilir. Kernel process'i OOM kill ile sonlandırabilir. Heap için bütün container RAM'i ayrılmamalıdır. RSS ve container usage aynı dashboard'da izlenmelidir.
Kubernetes OOMKilled Node.js'te nasıl çözülür?
Önce V8 OOM ile container OOM ayrılır. Pod events, memory limit, RSS ve heap trendleri incelenir. Heap leak varsa snapshot, native growth varsa farklı profiler kullanılır. Memory budget ve headroom yeniden doğrulanır. Sadece memory limit artırmak root cause çözümü değildir.
Node.js memory monitoring nasıl yapılır?
`process.memoryUsage()` ve V8 statistics temel application metric'leri sağlar. Prometheus RSS, heapUsed, external ve GC verilerini toplayabilir. Grafana container limit ve request latency ile birlikte gösterir. Growth rate ve sustained utilization alert üretebilir. OOM ve restart count ayrı reliability metric olmalıdır.
Node.js memory regression testi nasıl yapılır?
Healthy baseline ve candidate aynı workload altında çalıştırılır. Warm-up, request count ve concurrency eşit tutulur. Peak RSS ve test sonu heap baseline karşılaştırılır. Allowed threshold aşılırsa pipeline fail edilir. Scheduled soak test yavaş leak'leri ayrıca yakalar.
Kurumsal Node.js için JavaScript mi TypeScript mi?
Her ikisi de aynı Node.js ve V8 runtime üzerinde çalışır. TypeScript büyük codebase'de type safety ve refactor kolaylığı sağlar. Memory leak davranışını otomatik ortadan kaldırmaz. Resource lifecycle ve bounded collection kuralları yine gerekir. Kurumsal ekiplerde TypeScript çoğu zaman bakım avantajı sağlar.
Node.js yazılımcısı olmak için ne öğrenilmeli?
JavaScript ve TypeScript temeline event loop, async programming ve streams eklenmelidir. V8 ve garbage collection memory davranışını açıklar. SQL, Docker ve Kubernetes production altyapısını tamamlar. Prometheus ve profiling araçları incident çözmeyi öğretir. Gerçek load ve soak test içeren proje güçlü pratik sağlar.
Open source ve işbirliği Node.js kariyerine nasıl katkı sağlar?
Gerçek issue ve pull request'ler production edge case'lerini görmeyi sağlar. Minimal reproduction hazırlamak debugging becerisini geliştirir. Benchmark paylaşmak teknik düşünceyi ölçülebilir hâle getirir. Maintainer review farklı çözüm yaklaşımları gösterir. Küçük düzenli katkılar uzun vadede güçlü teknik portföy oluşturur.
Kurumsal Node.js projelerinde bellek (Memory) yönetimi nasıl optimize edilir?
Önce process memory RSS, heap, external ve Buffer alanlarına ayrılmalıdır. Cache, queue ve concurrency bounded hâle getirilmelidir. Büyük file ve dataset stream veya batch ile işlenmelidir. Container limit ile V8 heap arasında native memory için yeterli headroom bırakılmalıdır. Optimization her değişiklikten sonra load, soak ve memory regression testleriyle ölçülmelidir.
Node.js uygulamalarında memory leak nasıl tespit edilir ve giderilir?
İlk olarak GC sonrasında yükselmeye devam eden memory baseline doğrulanmalıdır. Problem aynı workload ile staging ortamında reproduce edilir. Heap snapshot comparison retaining path'i, allocation profile ise object'in oluşturulduğu code path'i bulmaya yardımcı olur. Root reference cache, listener veya timer seviyesinde düzeltilir. Fix aynı soak test ve production canary ile yeniden doğrulanır.
V8 Heap, Garbage Collection ve --max-old-space-size ayarları Node.js bellek performansını nasıl etkiler?
Heap büyüklüğü garbage collector'ın ne kadar sık çalışacağını ve live object set için ne kadar alan bulunduğunu etkiler. Çok küçük heap frequent GC oluşturabilir, gereksiz büyük heap ise container headroom'unu azaltabilir. `--max-old-space-size` toplam RSS'i değil V8 old memory alanını sınırlar. Buffer ve native memory bu sınır dışında kalabilir. Doğru değer P99 latency, GC pause, RSS ve throughput birlikte benchmark edilerek belirlenmelidir.
Production ortamında Heap Snapshot ve bellek metrikleri kullanılarak yüksek RAM tüketimi nasıl analiz edilir?
Önce RSS, heapUsed, external ve arrayBuffers grafikleri memory probleminin türünü daraltır. HeapUsed yükseliyorsa leak pattern doğrulanıp izole replica üzerinde snapshot comparison yapılabilir. Heap stable fakat RSS artıyorsa native memory veya fragmentation araştırılır. Snapshot process'i bloke edip ek memory tüketebildiği için replica traffic'ten çıkarılmalıdır. Diagnostic report daha düşük riskli ilk artifact olarak kullanılabilir.
Kurumsal Node.js projelerinde bellek optimizasyonu ve performans analizi konusunda yakınımda danışmanlık veya eğitim nerede bulabilirim?
Node.js performans ve backend danışmanlığı yakınımda araması yaparken yalnız heap limit değiştiren değil profiling, load test, container memory ve observability konularını birlikte ele alan bir yaklaşım aranmalıdır. Kurumsal Node.js bellek ve performans optimizasyon hizmeti mevcut production metriklerinin baseline alınmasıyla başlamalıdır. Diyarbakır'da backend geliştirme, açık kaynak ve performans çalışmaları için Diyarbakır Yazılım Topluluğu üzerinden teknik içerik ve proje çalışmalarına ulaşılabilir. Topluluk hakkında https://www.diyarbakiryazilim.com.tr/about adresinden bilgi alınabilir. Uygulamalı proje örnekleri için https://www.diyarbakiryazilim.com.tr/projects sayfası incelenebilir.
Sonuç: Kurumsal Node.js'te Bellek Yönetimi Leak Düzeltmekten Daha Fazlasıdır
Kurumsal Node.js Projelerinde Bellek (Memory) Yönetimi yalnız heap snapshot açıp büyük object aramakla sınırlı değildir. Sağlıklı production sistemi process memory bileşenlerini doğru ölçer, sınırsız resource'ları architecture seviyesinde engeller ve container memory için açık bir budget tanımlar. Leak investigation kadar streams, concurrency limit, queue control ve graceful shutdown da memory güvenliğinin parçasıdır. Memory regression ve soak testleri release pipeline'a eklendiğinde sorunlar kullanıcıya ulaşmadan fark edilebilir. Node.js backend architecture, performans ölçümü ve ortak teknik çalışmalar için https://www.diyarbakiryazilim.com.tr adresi üzerinden Diyarbakır Yazılım Topluluğu'na ulaşabilirsiniz.
Önce Process Belleğini Doğru Metriklere Ayırın
İlk adım RSS ile heapUsed değerini aynı şey kabul etmemektir. External ve arrayBuffers binary workload hakkında ek bilgi sağlar. Container cgroup metriği process seviyesindeki ölçümü tamamlar. GC ve latency user impact'i gösterir. Doğru metric ayrımı yanlış profiler ile saatler kaybetmeyi önler.
Heap, Native Memory ve Buffer'ı Ayrı İzleyin
JavaScript object leak heapUsed trendinde daha belirgin görünür. Buffer problemi external ve arrayBuffers tarafında öne çıkabilir. Native addon veya fragmentation yalnız RSS growth üretebilir. Her pattern farklı diagnostic tool ister. Dashboard bu üç alanı yan yana göstermelidir.
Sınırsız Kaynakları Mimari Seviyede Engelleyin
Cache, queue, listener ve connection sayısı açık limitlere sahip olmalıdır. Her collection için maximum growth sorusu code review'da sorulmalıdır. TTL tek başına peak capacity garantisi değildir. Load shedding overload sırasında availability'yi korur. Bounded architecture leak riskini daha code çalışmadan azaltır.
Streams ve Backpressure ile Büyük Veriyi Kontrollü İşleyin
Büyük file ve result set RAM'e tek parça alınmamalıdır. Stream producer consumer hızını backpressure üzerinden dengeler. `pipeline()` error ve cleanup management'ı kolaylaştırır. highWaterMark benchmark ile belirlenir. Böylece payload büyüklüğü process peak memory'sini doğrudan belirlemez.
Container Memory ile V8 Heap Arasında Headroom Bırakın
Heap toplam process memory değildir. Buffer, native code ve thread stack için RAM gerekir. Container limitin tamamını old space'e vermek OOM riskini artırır. Actual heap limit runtime'da ölçülmelidir. Headroom production load ve canary sonuçlarıyla doğrulanmalıdır.
Heap Snapshot'ı Kontrollü Bir Incident Aracı Olarak Kullanın
Snapshot sürekli monitoring aracı değildir. Event loop'u bloklayabilir ve önemli ek memory kullanabilir. Leak gösteren replica traffic'ten çıkarılmalıdır. Artifact token ve PII içerebileceği için güvenli saklanmalıdır. Snapshot comparison retaining path bulmak için kontrollü biçimde kullanılmalıdır.
Memory Regression ve Soak Testlerini CI/CD Sürecine Ekleyin
Kısa regression test büyük memory farklarını hızlı yakalar. Uzun soak test slow leak'leri ortaya çıkarır. Baseline ve candidate aynı workload altında karşılaştırılmalıdır. Allowed growth threshold historical variance üzerinden seçilir. Failure durumunda profile artifact investigation'ı hızlandırır.
Memory Kullanımını Availability ve Latency SLO'larının Bir Parçası Yapın
Memory pressure GC pause ve P99 latency üzerinden kullanıcıya yansır. OOM ve restart availability'yi doğrudan etkiler. Maximum RSS, heap utilization ve minimum headroom ölçülebilir SLO olabilir. Alert tek threshold yerine growth rate ve sustained duration kullanmalıdır. Böylece memory operasyon ekibinin düzenli reliability metriğine dönüşür.
Kurumsal Node.js Uygulamasını Memory Budget'ı Olan Bir Production Sistemi Olarak Tasarlayın
Memory budget application'ın ne kadar RAM kullanabileceğini açık engineering constraint hâline getirir. V8 heap, Buffer, native memory ve safety margin ayrı pay alır. Cache ve concurrency limitleri bu bütçeye göre seçilir. Canary ve observability gerçek traffic altında budget'ın korunduğunu doğrular. Bu yaklaşım memory problemlerine sonradan müdahale etmek yerine onları tasarım aşamasında sınırlandırır.
share: