GoDasturchi
Case Study: The Memory That Grows Overnight

Case Study: The Memory That Grows Overnight

Amaliy holat: kechasi bo'yicha o'sib boruvchi xotira

Restoranni tasavvur qiling: har bir mijoz ovqatlanib bo'lgach, ofitsiant idishlarni olib, YUVILMAGAN holda oshxona burchagiga qo'yib qo'yaveradi — hech qachon yuvmaydi. Birinchi kuni buni sezmaysiz, chunki burchak katta. Lekin har kuni idishlar to'planaverib, bir hafta ichida BUTUN oshxona ishlab bo'lmas holga keladi. Xotira sizib chiqishi (memory leak) — aynan shu: har bir "mijoz" (so'rov) o'zidan keyin bir oz "idish" (ishlatilmay qolgan xotira) qoldiradi, va hech kim uni "yuvmaydi" (tozalamaydi).

Stsenariy: sizning HTTP serveringiz bir necha kun ishlagandan keyin sekinlashib, oxir-oqibat xotira yetishmasligi (out of memory) tufayli qulab tushmoqda. Server qayta ishga tushirilgach, hammasi yana normal ishlaydi — bir necha kungacha.

cache.go
var requestLog = make(map[string][]string)

func handleRequest(userID, action string) {
	// Har bir so'rovni tarixga yozib boramiz — debug uchun foydali
	requestLog[userID] = append(requestLog[userID], action)

	// ...so'rovni qayta ishlash...
}

Bu yerdagi muammo — Reading a Stack Trace darsidagidek aniq "panic" chiqarmaydi, chunki bu XATO EMAS, balki SEKIN o'sib boruvchi holat. Guessing vs Forming a Hypothesis darsidagi kabi, gipoteza quramiz: "agar xotira vaqt o'tishi bilan o'ssa, demak biror joyda ma'lumot to'planib, hech qachon TOZALANMAYDI".

  • Isolating Variables darsidagi kabi: yukni (trafikni) o'zgarmas holda ushlab, faqat VAQTni o'zgaruvchi sifatida kuzating — xotira chiziqli o'sadimi, yoki barqarorlashadimi?
  • Go'ning pprof vositasi bilan xotira profilini ikki xil vaqtda oling va solishtiring — qaysi ma'lumotlar tuzilmasi ENG KO'P o'sganini ko'rasiz
  • requestLog xaritasi — aynan shu "cheksiz o'suvchi" tuzilma: har bir yangi userID uchun kalit qo'shiladi, lekin HECH QACHON o'chirilmaydi

Sabab topildi: requestLog — debug maqsadida qo'shilgan, lekin hech qachon tozalanmaydigan xarita. Har bir yangi foydalanuvchi va har bir amal unga qo'shiladi, lekin eski yozuvlar hech qachon o'chirilmaydi — xuddi yuvilmagan idishlar kabi. Yechim — yo bu jurnalni umuman olib tashlash (buning o'rniga slog bilan haqiqiy log yozish), yoki time.AfterFunc yordamida eski yozuvlarni muntazam "tozalab" turish.

Bu holat — muhim umumiy saboq beradi: kechasi bo'yicha o'sib boruvchi xotira deyarli har doim "biror joyda to'planib, hech qachon bo'shatilmaydigan" tuzilmani (xarita, slice, kesh) ko'rsatadi. Qidiruvni ANIQ shu turdagi tuzilmalardan boshlang — global o'zgaruvchilar, keshlar, buferlar — ular eng ko'p gumon qilinadigan joylar.

Key Takeaway

Key Takeaway:

Sekin, vaqt bilan o'sib boruvchi xotira muammosi — deyarli har doim biror joyda to'planib, hech qachon tozalanmaydigan tuzilmani (global xarita, kesh, buffer) ko'rsatadi. Vaqt bo'yicha o'zgarishni kuzatib va xotira profilini solishtirib, aybdor tuzilmani toping.

NEXT UP

Case Study: The Request That Times Out

Case Study: The Memory That Grows Overnight

Amaliy holat: kechasi bo'yicha o'sib boruvchi xotira

Restoranni tasavvur qiling: har bir mijoz ovqatlanib bo'lgach, ofitsiant idishlarni olib, YUVILMAGAN holda oshxona burchagiga qo'yib qo'yaveradi — hech qachon yuvmaydi. Birinchi kuni buni sezmaysiz, chunki burchak katta. Lekin har kuni idishlar to'planaverib, bir hafta ichida BUTUN oshxona ishlab bo'lmas holga keladi. Xotira sizib chiqishi (memory leak) — aynan shu: har bir "mijoz" (so'rov) o'zidan keyin bir oz "idish" (ishlatilmay qolgan xotira) qoldiradi, va hech kim uni "yuvmaydi" (tozalamaydi).

Stsenariy: sizning HTTP serveringiz bir necha kun ishlagandan keyin sekinlashib, oxir-oqibat xotira yetishmasligi (out of memory) tufayli qulab tushmoqda. Server qayta ishga tushirilgach, hammasi yana normal ishlaydi — bir necha kungacha.

cache.go
var requestLog = make(map[string][]string)

func handleRequest(userID, action string) {
	// Har bir so'rovni tarixga yozib boramiz — debug uchun foydali
	requestLog[userID] = append(requestLog[userID], action)

	// ...so'rovni qayta ishlash...
}

Bu yerdagi muammo — Reading a Stack Trace darsidagidek aniq "panic" chiqarmaydi, chunki bu XATO EMAS, balki SEKIN o'sib boruvchi holat. Guessing vs Forming a Hypothesis darsidagi kabi, gipoteza quramiz: "agar xotira vaqt o'tishi bilan o'ssa, demak biror joyda ma'lumot to'planib, hech qachon TOZALANMAYDI".

  • Isolating Variables darsidagi kabi: yukni (trafikni) o'zgarmas holda ushlab, faqat VAQTni o'zgaruvchi sifatida kuzating — xotira chiziqli o'sadimi, yoki barqarorlashadimi?
  • Go'ning pprof vositasi bilan xotira profilini ikki xil vaqtda oling va solishtiring — qaysi ma'lumotlar tuzilmasi ENG KO'P o'sganini ko'rasiz
  • requestLog xaritasi — aynan shu "cheksiz o'suvchi" tuzilma: har bir yangi userID uchun kalit qo'shiladi, lekin HECH QACHON o'chirilmaydi

Sabab topildi: requestLog — debug maqsadida qo'shilgan, lekin hech qachon tozalanmaydigan xarita. Har bir yangi foydalanuvchi va har bir amal unga qo'shiladi, lekin eski yozuvlar hech qachon o'chirilmaydi — xuddi yuvilmagan idishlar kabi. Yechim — yo bu jurnalni umuman olib tashlash (buning o'rniga slog bilan haqiqiy log yozish), yoki time.AfterFunc yordamida eski yozuvlarni muntazam "tozalab" turish.

Bu holat — muhim umumiy saboq beradi: kechasi bo'yicha o'sib boruvchi xotira deyarli har doim "biror joyda to'planib, hech qachon bo'shatilmaydigan" tuzilmani (xarita, slice, kesh) ko'rsatadi. Qidiruvni ANIQ shu turdagi tuzilmalardan boshlang — global o'zgaruvchilar, keshlar, buferlar — ular eng ko'p gumon qilinadigan joylar.

Key Takeaway

Key Takeaway:

Sekin, vaqt bilan o'sib boruvchi xotira muammosi — deyarli har doim biror joyda to'planib, hech qachon tozalanmaydigan tuzilmani (global xarita, kesh, buffer) ko'rsatadi. Vaqt bo'yicha o'zgarishni kuzatib va xotira profilini solishtirib, aybdor tuzilmani toping.

NEXT UP

Case Study: The Request That Times Out