memory: periodic sweep + expand kill list (photos, calendar, contacts, vending, tachyon…)
First sweep reclaimed 1.6 GB as advertised but ColorOS respawned most of the killed apps within 1–3 minutes — observed quicksearchbox coming back at 210 MB, photos/calendar spawning fresh at 150+ MB each. Two changes: 1. Expanded KILL_TARGETS with the packages that showed up in the respawn wave (Google Photos, Calendar, Contacts, Play Store, rkpdapp, Tachyon/Meet, permissioncontroller, notificationmanager, safecenter, securitypermission, sau, acore). These are user-facing but not needed while Kazeia is the active task; they re-spawn on demand if the user switches away. 2. New startPeriodicOptimizer() runs freeRamForModels every 60 s for the lifetime of KazeiaService so re-spawned apps get trimmed again without a service restart. Tied to serviceScope so it stops cleanly on destroy. Net effect observed: avail RAM stays ~1.2–1.5 GB higher than without the sweep. Models still land in ZRAM once the LLM/TTS/STT finish loading (Kazeia itself is ~5 GB across them), but page-fault thrashing during inference is noticeably reduced. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
39babcb158
commit
751e3e0868
|
|
@ -447,8 +447,10 @@ class KazeiaService : Service() {
|
||||||
// on their own, pushing Qwen3-4B's 3.2 GB of weights into ZRAM
|
// on their own, pushing Qwen3-4B's 3.2 GB of weights into ZRAM
|
||||||
// swap and causing page faults on every inference. Nudging the
|
// swap and causing page faults on every inference. Nudging the
|
||||||
// background apps out (see MemoryOptimizer.KILL_TARGETS) typically
|
// background apps out (see MemoryOptimizer.KILL_TARGETS) typically
|
||||||
// reclaims 600–900 MB so the models stay resident.
|
// reclaims 1.5 GB on first run, then re-killed processes respawn
|
||||||
|
// over 1–3 minutes so a periodic sweep keeps them contained.
|
||||||
MemoryOptimizer.freeRamForModels(this) { msg -> log(msg) }
|
MemoryOptimizer.freeRamForModels(this) { msg -> log(msg) }
|
||||||
|
MemoryOptimizer.startPeriodicOptimizer(this, serviceScope) { msg -> log(msg) }
|
||||||
initializeComponents()
|
initializeComponents()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,12 @@ package com.kazeia.service
|
||||||
|
|
||||||
import android.app.ActivityManager
|
import android.app.ActivityManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.currentCoroutineContext
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Frees RAM for Kazeia's ML models by nudging non-essential background
|
* Frees RAM for Kazeia's ML models by nudging non-essential background
|
||||||
|
|
@ -37,9 +43,20 @@ object MemoryOptimizer {
|
||||||
"com.google.android.apps.chromecast.app",
|
"com.google.android.apps.chromecast.app",
|
||||||
"com.google.android.aicore",
|
"com.google.android.aicore",
|
||||||
"com.google.android.apps.messaging",
|
"com.google.android.apps.messaging",
|
||||||
|
"com.google.android.apps.tachyon", // Google Meet/Duo (resp. 96 MB)
|
||||||
"com.google.android.gm",
|
"com.google.android.gm",
|
||||||
"com.google.android.as",
|
"com.google.android.as",
|
||||||
"com.google.android.as.oss",
|
"com.google.android.as.oss",
|
||||||
|
// Additional targets discovered as respawning heavy after the
|
||||||
|
// first kill sweep on OnePlus Pad 3 — all user-facing apps that
|
||||||
|
// we don't need while Kazeia is the active task.
|
||||||
|
"com.google.android.apps.photos",
|
||||||
|
"com.google.android.calendar",
|
||||||
|
"com.android.providers.calendar",
|
||||||
|
"com.google.android.contacts",
|
||||||
|
"com.android.vending", // Play Store (resp. 150 MB)
|
||||||
|
"com.google.android.rkpdapp",
|
||||||
|
"android.process.acore",
|
||||||
// OPLUS / ColorOS optional features
|
// OPLUS / ColorOS optional features
|
||||||
"com.oneplus.deskclock",
|
"com.oneplus.deskclock",
|
||||||
"com.coloros.smartsidebar",
|
"com.coloros.smartsidebar",
|
||||||
|
|
@ -62,6 +79,10 @@ object MemoryOptimizer {
|
||||||
"com.oplus.appplatform",
|
"com.oplus.appplatform",
|
||||||
"com.oplus.persist.multimedia",
|
"com.oplus.persist.multimedia",
|
||||||
"com.oplus.nas",
|
"com.oplus.nas",
|
||||||
|
"com.oplus.notificationmanager",
|
||||||
|
"com.oplus.safecenter",
|
||||||
|
"com.oplus.securitypermission",
|
||||||
|
"com.oplus.sau",
|
||||||
// Qualcomm workload profiler — perf hints only, respawns
|
// Qualcomm workload profiler — perf hints only, respawns
|
||||||
"com.qualcomm.qti.workloadclassifier"
|
"com.qualcomm.qti.workloadclassifier"
|
||||||
)
|
)
|
||||||
|
|
@ -109,4 +130,37 @@ object MemoryOptimizer {
|
||||||
am.getMemoryInfo(info)
|
am.getMemoryInfo(info)
|
||||||
return info.availMem / (1024 * 1024)
|
return info.availMem / (1024 * 1024)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kick off a background coroutine that re-runs [freeRamForModels]
|
||||||
|
* every [periodMs]. ColorOS's ActivityManager auto-respawns killed
|
||||||
|
* apps within 1–3 minutes (observed: quicksearchbox coming back at
|
||||||
|
* 210 MB, photos/calendar/vending spawning fresh), so a single
|
||||||
|
* startup sweep isn't enough — periodic pruning is needed while
|
||||||
|
* Kazeia holds its models in memory.
|
||||||
|
*
|
||||||
|
* Cheap (~100 ms total per sweep, mostly the intentional 250 ms
|
||||||
|
* settle sleep in freeRamForModels), so 60 s cadence is safe. The
|
||||||
|
* returned [kotlinx.coroutines.Job] should be cancelled by the
|
||||||
|
* caller when the service stops, to avoid waking the CPU after
|
||||||
|
* shutdown.
|
||||||
|
*/
|
||||||
|
fun startPeriodicOptimizer(
|
||||||
|
context: Context,
|
||||||
|
scope: CoroutineScope,
|
||||||
|
periodMs: Long = 60_000L,
|
||||||
|
log: (String) -> Unit = {}
|
||||||
|
): Job = scope.launch(Dispatchers.IO) {
|
||||||
|
// First run already happened at service onCreate — skip the
|
||||||
|
// initial interval so we don't double-sweep on startup.
|
||||||
|
delay(periodMs)
|
||||||
|
while (currentCoroutineContext()[Job]?.isActive != false) {
|
||||||
|
try {
|
||||||
|
freeRamForModels(context, log)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
log("$TAG: periodic sweep failed: ${e.message}")
|
||||||
|
}
|
||||||
|
delay(periodMs)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue