Skip to content

sysmon

sysmon yaygın bir fonksiyondur, kelimenin tam anlamıyla sistem izleyici olarak çevrilir. Yorum kısımları kaldırıldığında, sadece yaklaşık 200 satır koddur. Program önyükleme aşamasında ayrı bir iş parçacığına başlatmak için atanır ve sonra arka planda Go programı runtime durumunu sürekli izler ve buna göre işlem yapar. Başlatma kodu runtime.main fonksiyonunda görüntülenebilir:

go
func main() {
    ...
  mp := getg().m
  mainStarted = true
  systemstack(func() {
        newm(sysmon, nil, -1)
    })
    ...
}

Sistem izleyici kendisi sadece bir for döngüsüdür. Her döngü turu arasındaki aralık 20 mikrosaniyedir ve program boşta kalma indeksi arttıkça, aralık süresi maksimum 10 milisaniyeye kadar artar. Döngünün her turunda, principalmente aşağıdaki işleri yapar:

  • Goroutine zamanlamasına yardımcı olur, uzun süre çalışan goroutine'leri önler
  • Bellek koşullarını kontrol eder ve çöp toplamaya ihtiyaç olup olmadığını belirler
  • Ağ poller koşullarını kontrol eder ve zamanlanmış bekleyen goroutine'leri işler
  • Kullanılmayan belleği temizler ve işletim sistemine iade eder
  • Yığın profili bilgilerini temizler
  • mcache arabelleklerini bırakır

Önleme

Önleme işi runtime.preemptone fonksiyonu tarafından tamamlanır. Principalmente mevcut goroutine'in çalışma süresinin sınırı aşıp aşmadığını kontrol eder. Eğer aşarsa, goroutine'in preempt alanını true olarak ayarlar, bu önlenmesi gerektiğini gösterir.

go
func preemptone(pp *p) bool {
  mp := pp.m.ptr()
  if mp == nil || mp == getg().m {
    return false
  }
  gp := mp.curg
  if gp == nil || gp == mp.g0 {
    return false
  }

  gp.preempt = true

  // Every call in a goroutine should check for preemption now.
  gp.stackguard0 = stackPreempt

  return true
}

Goroutine'in stackguard0 alanı önlemeye ihtiyaç olup olmadığını kontrol etmek için kullanılır. stackPreempt olarak ayarlandığında, goroutine'in önlenmesi gerektiğini gösterir. Bu yığın genişletme kontrolleri için mekanizmadır. Bir goroutine'in yığını genişletmesi gerektiğinde, stackguard0stackPreempt olarak ayarlar. Goroutine bir fonksiyon çağırdığında, stackguard0'ın stackPreempt olup olmadığını kontrol eder. Eğer öyleyse, yığın genişletmeyi tetikler. Ancak goroutine uzun süre fonksiyon çağırmazsa, yığın genişletme kontrollerini tetikleyemez. Bu yüzden sistem izleyici bu durumu kontrol etmelidir.

go
func goschedImpl(gp *g, inheritTime bool) {
  ...
  casgstatus(gp, _Grunning, _Grunnable)
  if !inheritTime {
    gp.schedtick++
  }
  globrunq.put(gp, 0)
  schedule()
}

Bir goroutine önlendiğinde, durumu _Grunning'den _Grunnable'a değiştirilir, sonra yeniden zamanlanma için beklemek üzere global çalıştırılabilir kuyruğa konur.

Çöp Toplama

Sistem izleyici periyodik olarak çöp toplamaya ihtiyaç olup olmadığını kontrol eder. Son çöp toplamadan bu yana geçen süre sınırı aşarsa, zorla çöp toplamayı tetikler. Bu zaman sınırı runtime.forcegcperiod sabiti tarafından belirlenir, bu 2 dakikadır.

go
func sysmon() {
  ...
  for {
    ...
    // check if we need to force a GC
    if t := (gcTrigger{kind: gcTriggerTime, now: now}); t.test() && forcegc.idle.Load() {
      lock(&forcegc.lock)
      forcegc.idle.Store(false)
      var list gList
      list.push(forcegc.g)
      injectglist(&list)
      unlock(&forcegc.lock)
    }
    ...
  }
}

Çöp toplama tetiklendiğinde, çöp toplama işini yürütmek için forcegc goroutine'i uyandırılır.

Ağ Poller

Sistem izleyici ayrıca periyodik olarak ağ poller'ın koşullarını kontrol eder. Zamanlanmış bekleyen goroutine'ler varsa, onları işler. Bu iş kısmı runtime.netpoll fonksiyonu tarafından tamamlanır.

go
func sysmon() {
  ...
  for {
    ...
    // poll network
    npoll := netpoll(-1)
    if npoll != 0 {
      npollcnt++
    }
    ...
  }
}

Ağ poller zamanlanmış bekleyen goroutine'lere sahip olduğunda, yürütmeye devam etmeleri için uyandırılırlar.

Bellek Temizleme

Sistem izleyici ayrıca periyodik olarak kullanılmayan belleği temizler ve işletim sistemine iade eder. Bu iş kısmı runtime.mheap.scavenge fonksiyonu tarafından tamamlanır.

go
func sysmon() {
  ...
  for {
    ...
    // scavenge heap
    if scavengeHeap() {
      scavengeCnt++
    }
    ...
  }
}

Yığında kullanılmayan bellek olduğunda, bellek kullanımını azaltmak için işletim sistemine iade edilir.

Diğer İşler

Sistem izleyici ayrıca bazı diğer işleri de yapar, örneğin yığın profili bilgilerini temizlemek, mcache arabelleklerini bırakmak vb. Bu görevler sistem izleyicinin ana işi değildir, ancak bunlar da gereklidir.

go
func sysmon() {
  ...
  for {
    ...
    // flush heap profile
    if shouldFlushHeapProfile() {
      flushHeapProfile()
    }
    // drop mcache buffers
    if shouldDropMcache() {
      dropMcache()
    }
    ...
  }
}

Genel olarak, sistem izleyici Go runtime'ın önemli bir parçasıdır. Go programı runtime durumunu izler ve Go programının kararlı çalışmasını sağlamak için buna göre işlem yapar.

Golang by www.golangdev.cn edit