service_timer.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. package oomkiller
  2. import (
  3. runtimeDebug "runtime/debug"
  4. "sync"
  5. "time"
  6. "github.com/sagernet/sing-box/adapter"
  7. "github.com/sagernet/sing-box/log"
  8. "github.com/sagernet/sing/common/memory"
  9. )
  10. const (
  11. defaultChecksBeforeLimit = 4
  12. defaultMinInterval = 500 * time.Millisecond
  13. defaultMaxInterval = 10 * time.Second
  14. defaultSafetyMargin = 5 * 1024 * 1024
  15. )
  16. type adaptiveTimer struct {
  17. logger log.ContextLogger
  18. router adapter.Router
  19. memoryLimit uint64
  20. safetyMargin uint64
  21. minInterval time.Duration
  22. maxInterval time.Duration
  23. checksBeforeLimit int
  24. useAvailable bool
  25. access sync.Mutex
  26. timer *time.Timer
  27. previousUsage uint64
  28. lastInterval time.Duration
  29. }
  30. type timerConfig struct {
  31. memoryLimit uint64
  32. safetyMargin uint64
  33. minInterval time.Duration
  34. maxInterval time.Duration
  35. checksBeforeLimit int
  36. useAvailable bool
  37. }
  38. func newAdaptiveTimer(logger log.ContextLogger, router adapter.Router, config timerConfig) *adaptiveTimer {
  39. return &adaptiveTimer{
  40. logger: logger,
  41. router: router,
  42. memoryLimit: config.memoryLimit,
  43. safetyMargin: config.safetyMargin,
  44. minInterval: config.minInterval,
  45. maxInterval: config.maxInterval,
  46. checksBeforeLimit: config.checksBeforeLimit,
  47. useAvailable: config.useAvailable,
  48. }
  49. }
  50. func (t *adaptiveTimer) start(_ uint64) {
  51. t.access.Lock()
  52. defer t.access.Unlock()
  53. t.startLocked()
  54. }
  55. func (t *adaptiveTimer) startNow() {
  56. t.access.Lock()
  57. t.startLocked()
  58. t.access.Unlock()
  59. t.poll()
  60. }
  61. func (t *adaptiveTimer) startLocked() {
  62. if t.timer != nil {
  63. return
  64. }
  65. t.previousUsage = memory.Total()
  66. t.lastInterval = t.minInterval
  67. t.timer = time.AfterFunc(t.minInterval, t.poll)
  68. }
  69. func (t *adaptiveTimer) stop() {
  70. t.access.Lock()
  71. defer t.access.Unlock()
  72. t.stopLocked()
  73. }
  74. func (t *adaptiveTimer) stopLocked() {
  75. if t.timer != nil {
  76. t.timer.Stop()
  77. t.timer = nil
  78. }
  79. }
  80. func (t *adaptiveTimer) running() bool {
  81. t.access.Lock()
  82. defer t.access.Unlock()
  83. return t.timer != nil
  84. }
  85. func (t *adaptiveTimer) poll() {
  86. t.access.Lock()
  87. defer t.access.Unlock()
  88. if t.timer == nil {
  89. return
  90. }
  91. usage := memory.Total()
  92. delta := int64(usage) - int64(t.previousUsage)
  93. t.previousUsage = usage
  94. var remaining uint64
  95. var triggered bool
  96. if t.memoryLimit > 0 {
  97. if usage >= t.memoryLimit {
  98. remaining = 0
  99. triggered = true
  100. } else {
  101. remaining = t.memoryLimit - usage
  102. }
  103. } else if t.useAvailable {
  104. available := memory.Available()
  105. if available <= t.safetyMargin {
  106. remaining = 0
  107. triggered = true
  108. } else {
  109. remaining = available - t.safetyMargin
  110. }
  111. } else {
  112. remaining = 0
  113. }
  114. if triggered {
  115. t.logger.Error("memory threshold reached, usage: ", usage/(1024*1024), " MiB, resetting network")
  116. t.router.ResetNetwork()
  117. runtimeDebug.FreeOSMemory()
  118. }
  119. var interval time.Duration
  120. if triggered {
  121. interval = t.maxInterval
  122. } else if delta <= 0 {
  123. interval = t.maxInterval
  124. } else if t.checksBeforeLimit <= 0 {
  125. interval = t.maxInterval
  126. } else {
  127. timeToLimit := time.Duration(float64(remaining) / float64(delta) * float64(t.lastInterval))
  128. interval = timeToLimit / time.Duration(t.checksBeforeLimit)
  129. if interval < t.minInterval {
  130. interval = t.minInterval
  131. }
  132. if interval > t.maxInterval {
  133. interval = t.maxInterval
  134. }
  135. }
  136. t.lastInterval = interval
  137. t.timer.Reset(interval)
  138. }