问题
最近有个小需求,能通过自动化对app进行GC回收
对于app的处理无外乎主动调用System.gc()或者使用adb命令直接进行GC回收
解决方法
方法一
在代码里的某个方法调用System.gc(),如我申明一个receiver,然后通过接受外不广播,去调用System.gc()完成gc回收的触发,如
public class GCReceiver extends BroadcastReceiver {
private static final String TAG = "GCReceiver";
private static final String ACTION_GC = "com.tomes.ACTION_GC";
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.i(TAG, "onReceive: " + action);
if (ACTION_GC.equals(action)) {
System.gc();
}
}
}
<receiver
android:name="com.tomes.GCReceiver">
<intent-filter>
<action android:name="com.tomes.ACTION_GC" />
</intent-filter>
</receiver>
需要触发的时候,只需要执行adb命令
adb shell am broadcast -a com.tomes.ACTION_GC -f 0x01000000 --es configs 0xCF0400
方法二
有没有不要额外给app编码的方法去触发gc回收呢?有的
直接上答案,adb shell进入手机的shell环境
kill -10 应用pid
触发结果如下:
2022-03-31 14:42:43.750 13997-14011/com.tomes.gctest I/.tomes.gctest: SIGUSR1 forcing GC (no HPROF) and profile save
2022-03-31 14:42:43.782 13997-14011/com.tomes.gctest I/.tomes.gctest: Explicit concurrent copying GC freed 44(32KB) AllocSpace objects, 0(0B) LOS objects, 79% free, 1577KB/7721KB, paused 92us total 31.781ms
有些小伙伴在执行kill -10 时可能会提示
sh: kill: 13997: Permission denied
这时,你需要权限,root手机可以切换到root用户,非root手机的,在app是debug模式时
则可以执行run-as命令去拿到权限
run-as 包名
kill -10 GC的原理探究
查看as如何强制触发gc的
源码如下(由于源码很清晰,所以不再做额外的解释):
//bionic/libc/kernel/uapi/asm-x86/asm/signal.h
//定义信号量
#define SIGUSR1 10
//art/runtime/signal_catcher.cc
void* SignalCatcher::Run(void* arg) {
SignalCatcher* signal_catcher = reinterpret_cast<SignalCatcher*>(arg);
CHECK(signal_catcher != nullptr);
Runtime* runtime = Runtime::Current();
CHECK(runtime->AttachCurrentThread("Signal Catcher", true, runtime->GetSystemThreadGroup(),
!runtime->IsAotCompiler()));
Thread* self = Thread::Current();
DCHECK_NE(self->GetState(), ThreadState::kRunnable);
{
MutexLock mu(self, signal_catcher->lock_);
signal_catcher->thread_ = self;
signal_catcher->cond_.Broadcast(self);
}
// Set up mask with signals we want to handle.
SignalSet signals;
signals.Add(SIGQUIT);
signals.Add(SIGUSR1);
while (true) {
int signal_number = signal_catcher->WaitForSignal(self, signals);
if (signal_catcher->ShouldHalt()) {
runtime->DetachCurrentThread();
return nullptr;
}
switch (signal_number) {
case SIGQUIT:
signal_catcher->HandleSigQuit();
break;
//处理接收到的信号量10
case SIGUSR1:
//强制GC回收
signal_catcher->HandleSigUsr1();
break;
default:
LOG(ERROR) << "Unexpected signal %d" << signal_number;
break;
}
}
}
//art/runtime/signal_catcher.cc
void SignalCatcher::HandleSigUsr1() {
//这里我们能看到系统里打印出来的日志,作为佐证
LOG(INFO) << "SIGUSR1 forcing GC (no HPROF) and profile save";
Runtime::Current()->GetHeap()->CollectGarbage(/* clear_soft_references= */ false);
ProfileSaver::ForceProcessProfiles();
}