当前位置: 首页 > news >正文

Android 系统启动过程纪要(基于Android 10)

前言

看过源码的都知道,Launcher系统启动都会经过这三个进程 init ->zygote -> system_server。今天我们就来讲解一下这三个进程以及Launcher系统启动。

init进程

  1. 准备Android虚拟机环境:创建和挂载系统文件目录;
  2. 初始化属性服务;
  3. 设置子进程信号处理函数(防止init的子进程出现僵尸进程,在子进程暂停和结束是接受信号并进行处理);

僵尸进程:父进程使用fork创建子进程,如果子进程终止,但父进程并不知道已经终止。虽然此时子进程已经退出,但是还是保留了他的信息(进程号。退出状态。运行时间等)。这样,系统进程表就会被无端耗用如果耗尽之后,系统可能就无法再创建新的进程。

  1. 启动属性服务,并为其分配内存用来存储属性:使用一个键值对(注册表)记录用户\软件的一些使用信息(确保系统或者软件重启之后能根据注册表中的信息进行初始化的工作)
  2. 解析init.rc配置文件。 解析init.zygote脚本文件,启动zygote进程

总的来说做了三件事:

  1. 创建和挂在系统启动所需要的文件目录;
  2. 初始化和启动属性服务;
  3. 解析init.rc配置文件并启动zygote进程。

zygote进程

init通过调用app_main.cpp的main函数中的start方法来启动zygote进程。
在这里插入图片描述
DVM,ART,应用程序进程以及SystemServer进程都是有zygote创建。通过fork自身(从zygote进程)来创建新的应用进程。因此,zygote进程和它的子进程都会运行main函数。main函数里会通过标记查看main函数是运行在zygote进程还是子进程。如果实在zygote进程里,那么就会调用AppRuntime的start函数。在start函数里,会创建Java虚拟机以及做一些其他的准备工作。最后通过JNI调用ZygoteInit.java里的mian方法,进入Java框架层。

main方法主要做下面几件事情:

  1. 创建一个Server端的Socket,用来等待AMS请求创建新的应用进程;
  2. 预加载类和资源;
  3. 启动SystemServer进程;
  4. 等待AMS请求创建新的应用程序进程(通过无限循环while(true)等待AMS的请求)。

SystemServer(zygote第一个启动的进程)

SystemServer主要用来创建系统服务,例如AMS,WMS都是有他创建的。Zygote进程通过forkSystemServetr方法复制Zygote进程的地址空间,并关闭SystemServer不需要的Socket进程。然后通过handleSystemServerProcess方法启动进程。

//ZygoteInit.java
private static Runnable forkSystemServer(String abiList, String socketName,ZygoteServer zygoteServer) {String[] args = {"--setuid=1000","--setgid=1000","--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,"+ "1024,1032,1065,3001,3002,3003,3006,3007,3009,3010,3011,3012","--capabilities=" + capabilities + "," + capabilities,"--nice-name=system_server","--runtime-args","--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,"com.android.server.SystemServer",};ZygoteArguments parsedArgs;try {ZygoteCommandBuffer commandBuffer = new ZygoteCommandBuffer(args);try {parsedArgs = ZygoteArguments.getInstance(commandBuffer);} catch (EOFException e) {throw new AssertionError("Unexpected argument error for forking system server", e);}catch (IllegalArgumentException  e) {}       int pid;try {//.../* Request to fork the system server process */pid = Zygote.forkSystemServer(parsedArgs.mUid, parsedArgs.mGid,parsedArgs.mGids,parsedArgs.mRuntimeFlags,null,parsedArgs.mPermittedCapabilities,parsedArgs.mEffectiveCapabilities);} catch (IllegalArgumentException ex) {throw new RuntimeException(ex);}if (pid == 0) {if (hasSecondZygote(abiList)) {waitForSecondaryZygote(socketName);}//关闭Zygote进程创建的SocketzygoteServer.closeServerSocket();return handleSystemServerProcess(parsedArgs);}return null;}

在handleSystemServerProcess方法中,会启动Binder线程池,这样SystemServer就可以使用Binder和其他应用进程进程通讯。

//ZygoteInit.javaprivate static Runnable handleSystemServerProcess(ZygoteArguments parsedArgs) {///if (parsedArgs.mInvokeWith != null) {//} else {return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,parsedArgs.mDisabledCompatChanges,parsedArgs.mRemainingArgs, cl);}}
//ZygoteInit.javaprivate static Runnable handleSystemServerProcess(ZygoteArguments parsedArgs) {///if (parsedArgs.mInvokeWith != null) {//} else {return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,parsedArgs.mDisabledCompatChanges,parsedArgs.mRemainingArgs, cl);}}

启动Binder线程池之后,会调用RuntimeInit.applicationInit:

//RuntimeInit.javaprotected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges,String[] argv, ClassLoader classLoader) {//final Arguments args = new Arguments(argv);return findStaticMain(args.startClass, args.startArgs, classLoader);}

然后调用findStaticMain 方法:

	RuntimeInit.javaprotected static Runnable findStaticMain(String className, String[] argv,ClassLoader classLoader) {Class<?> cl;try {//使用反射创建SystemServer。cl = Class.forName(className, true, classLoader);} catch (ClassNotFoundException ex) {throw new RuntimeException("Missing class when invoking static main " + className,ex);}Method m;try {//找到ServerServer的main方法m = cl.getMethod("main", new Class[] { String[].class });} catch (NoSuchMethodException ex) {throw new RuntimeException("Missing static main on " + className, ex);} catch (SecurityException ex) {throw new RuntimeException("Problem getting static main on " + className, ex);}int modifiers = m.getModifiers();if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {throw new RuntimeException("Main method is not public and static on " + className);}//通过MethodAndArgsCaller调用SystemServer的main方法return new MethodAndArgsCaller(m, argv);}

可以看到,这里使用反射的方式创建了Systemserver,其中的className实在ZygoteInit.java类中forkSystemServer 方法的变量arg中初始化的。然后通过MethodAndArgsCaller来调用Systemserver的main方法,主要是为了能让ZygoteInit.mian能捕获异常(因为SystemServer的main方法在调用之前SystemServer进程已经做了很多准备工作,而如果慧姐抛出异常,则会清理掉所有的堆栈信帧,使得SystemServer的main看起来就不是SystemServer的入口方法了),MethodAndArgsCaller代码也很简单:

static class MethodAndArgsCaller implements Runnable {/** method to call */private final Method mMethod;/** argument array */private final String[] mArgs;public MethodAndArgsCaller(Method method, String[] args) {mMethod = method;mArgs = args;}public void run() {try {mMethod.invoke(null, new Object[] { mArgs });} catch (IllegalAccessException ex) {throw new RuntimeException(ex);} catch (InvocationTargetException ex) {Throwable cause = ex.getCause();if (cause instanceof RuntimeException) {throw (RuntimeException) cause;} else if (cause instanceof Error) {throw (Error) cause;}throw new RuntimeException(ex);}}}

而在ZygoteInit的main方法中,有该异常的捕获的try语句。

在SystemServer中,main方法的关键操作如下:


public static void main(String[] args) {new SystemServer().run();
}private void run() {//try {Looper.prepareMainLooper();Looper.getMainLooper().setSlowLogThresholdMs(SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);System.loadLibrary("android_servers");       createSystemContext();        }//// Start services.try {t.traceBegin("StartServices");startBootstrapServices(t);//启动引导服务startCoreServices(t);//启动核心服务startOtherServices(t);//启动其他服务} catch (Throwable ex) {throw ex;} finally {t.traceEnd(); // StartServices}Looper.loop();
}

SystemServer会创建消息Looper,加载库文件,并创建系统的Context。然后创建和启动各种系统服务:

  1. 引导服务:Installer、AMS、PMS等
  2. 核心服务:DropBoxManagerService、BatteryService等
  3. 其他服务:CameraService、WMS等

以PowerStatsService为例,通过SystemServiceManager的startService方法启动:mSystemServiceManager.startService(PowerStatsService.class);

SystemServiceManager:Manages creating, starting, and other lifecycle events of SystemService system services

   //SystemServiceManager.javaprivate final ArrayList<SystemService> mServices = new ArrayList<SystemService>();public <T extends SystemService> T startService(Class<T> serviceClass) {try {final String name = serviceClass.getName();final T service;try {Constructor<T> constructor = serviceClass.getConstructor(Context.class);service = constructor.newInstance(mContext);} catch (InvocationTargetException ex) {throw new RuntimeException("Failed to create service " + name+ ": service constructor threw an exception", ex);}startService(service);return service;} finally {Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);}}public void startService(@NonNull final SystemService service) {// Register it.mServices.add(service);// Start it.long time = SystemClock.elapsedRealtime();try {service.onStart();} catch (RuntimeException ex) {throw new RuntimeException("Failed to start service " + service.getClass().getName()+ ": onStart threw an exception", ex);}warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");}

通过创建service,然后将service添加到一个ArrayList中,这样就完成了注册工作。最后调用service的start方法启动。

SystemServer进程被创建后做了一下工作:

  1. 启动Binder线程池,用于和其他进程通讯;
  2. 创建SystemServerManager,用于系统服务的创建、启动和管理;
  3. 使用SystemServerManager启动各种服务。

负责拉起AMS等80多个服务

     try {traceBeginAndSlog("StartServices");startBootstrapServices();startCoreServices();startOtherServices();SystemServerInitThreadPool.shutdown();} catch (Throwable ex) {Slog.e("System", "******************************************");Slog.e("System", "************ Failure starting system services", ex);throw ex;} finally {traceEnd();}

在这里插入图片描述

finishBooting负责发送系统启动完成广播

为什么应用启动时要从zygote进程中fork: 若从init fork需要准备虚拟机,预加载类文件;若从system_server App进程不需要大量的服务(AMS WMS PMS等80多种服务)

Launcher启动

系统启动的最后一步是启动一个用来显示系统中已安装应用的应用程序——Launcher。通俗的讲,它就是Android的系统桌面,主要有以下两个特点:

  1. 作为Android系统的启动器,用于启动应用程序;
  2. 作为Android系统的桌面,用于显示和管理应用程序的快捷图标或者其他桌面组件。

在SystemServer启动过程中,由它启动的Ams(ActivityManagerService.)会将Launcher启动。Launcher的启动入口在SystemServer的startOtherServices方法中:

//SystemServer.java
// We now tell the activity manager it is okay to run third party
// code.  It will call back into us once it has gotten to the state
// where third party code can really run (but before it has actually
// started launching the initial applications), for us to complete our
// initialization.mActivityManagerService.systemReady(() -> {mSystemServiceManager.startBootPhase(t, SystemService.PHASE_ACTIVITY_MANAGER_READY);});

根据官方注释,我们可以看出,在这里系统服务已经就绪,到这里系统就算启动完成,可以跑第三方的代码了。此时,会调用AMS的systemReady方法,让AMS去启动Launcher。下面是ActivityManagerService.java中systemReady方法启动Launcher的关键代码:

public ActivityTaskManagerInternal mAtmInternal;public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {synchronized (this) {mAtmInternal.startHomeOnAllDisplays(currentUserId, "systemReady");}
}	

其中,mAtmInternal 的具体实现是:ActivityTaskManagerService.LocalService。是在ActivityTaskManagerService里的一个内部类。ActivityTaskManagerService.LocalService.startHomeOnAllDisplays代码如下:

@Override
public boolean startHomeOnAllDisplays(int userId, String reason) {synchronized (mGlobalLock) {return mRootActivityContainer.startHomeOnAllDisplays(userId, reason);}
}

RootActivityContainer.startHomeOnAllDisplays的代码如下:

boolean startHomeOnAllDisplays(int userId, String reason) {boolean homeStarted = false;// 由于Android系统支持多用户和多显示,调用startHomeOnAllDisplays启动每个display上的Home Activityfor (int i = mActivityDisplays.size() - 1; i >= 0; i--) {final int displayId = mActivityDisplays.get(i).mDisplayId;homeStarted |= startHomeOnDisplay(userId, reason, displayId);}return homeStarted;
}

继续追踪startHomeOnDisplay方法:

boolean startHomeOnDisplay(int userId, String reason, int displayId) {return startHomeOnDisplay(userId, reason, displayId, false /* allowInstrumenting */,false /* fromHomeKey */);
}boolean startHomeOnDisplay(int userId, String reason, int displayId, boolean allowInstrumenting,boolean fromHomeKey) {if (displayId == INVALID_DISPLAY) {displayId = getTopDisplayFocusedStack().mDisplayId;}Intent homeIntent = null;ActivityInfo aInfo = null;if (displayId == DEFAULT_DISPLAY) {//第一步:获取Intent//这里的mService就是ActivityTaskManagerServicehomeIntent = mService.getHomeIntent();aInfo = resolveHomeActivity(userId, homeIntent);} else if (shouldPlaceSecondaryHomeOnDisplay(displayId)) {Pair<ActivityInfo, Intent> info = resolveSecondaryHomeActivity(userId, displayId);aInfo = info.first;homeIntent = info.second;}if (aInfo == null || homeIntent == null) {return false;}if (!canStartHomeOnDisplay(aInfo, displayId, allowInstrumenting)) {return false;}homeIntent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));homeIntent.setFlags(homeIntent.getFlags() | FLAG_ACTIVITY_NEW_TASK);if (fromHomeKey) {homeIntent.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, true);}final String myReason = reason + ":" + userId + ":" + UserHandle.getUserId(aInfo.applicationInfo.uid) + ":" + displayId;//  第二步:启动    mService.getActivityStartController().startHomeActivity(homeIntent, aInfo, myReason,displayId);return true;
}

其中,第一步获取Intent的getHomeIntent方法在ActivityTaskManagerService中,代码如下:就是给Intent添加了Intent.CATEGORY_HOME属性

String mTopAction = Intent.ACTION_MAIN;Intent getHomeIntent() {Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);intent.setComponent(mTopComponent);intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {//返回一个Category为Intent.CATEGORY_HOME的Intentintent.addCategory(Intent.CATEGORY_HOME);}return intent;}

接下来第二步,startHomeActivity方法在ActivityStartController中,关键代码入下:

void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason, int displayId) {final ActivityOptions options = ActivityOptions.makeBasic();options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);if (!ActivityRecord.isResolverActivity(aInfo.name)) { options.setLaunchActivityType(ACTIVITY_TYPE_HOME);}options.setLaunchDisplayId(displayId);mLastHomeActivityStartResult = obtainStarter(intent, "startHomeActivity: " + reason).setOutActivity(tmpOutRecord).setCallingUid(0).setActivityInfo(aInfo).setActivityOptions(options.toBundle()).execute();//启动
}

其中,最后的execute最终是执行的ActivityStarter的execute代码:

 /*** Starts an activity based on the request parameters provided earlier.* @return The starter result.*/int execute() {try {// TODO(b/64750076): Look into passing request directly to these methods to allow// for transactional diffs and preprocessing.if (mRequest.mayWait) {return startActivityMayWait(mRequest.caller, mRequest.callingUid,mRequest.callingPackage, mRequest.realCallingPid, mRequest.realCallingUid,mRequest.intent, mRequest.resolvedType,mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,mRequest.resultWho, mRequest.requestCode, mRequest.startFlags,mRequest.profilerInfo, mRequest.waitResult, mRequest.globalConfig,mRequest.activityOptions, mRequest.ignoreTargetSecurity, mRequest.userId,mRequest.inTask, mRequest.reason,mRequest.allowPendingRemoteAnimationRegistryLookup,mRequest.originatingPendingIntent, mRequest.allowBackgroundActivityStart);} else {return startActivity(mRequest.caller, mRequest.intent, mRequest.ephemeralIntent,mRequest.resolvedType, mRequest.activityInfo, mRequest.resolveInfo,mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,mRequest.resultWho, mRequest.requestCode, mRequest.callingPid,mRequest.callingUid, mRequest.callingPackage, mRequest.realCallingPid,mRequest.realCallingUid, mRequest.startFlags, mRequest.activityOptions,mRequest.ignoreTargetSecurity, mRequest.componentSpecified,mRequest.outActivity, mRequest.inTask, mRequest.reason,mRequest.allowPendingRemoteAnimationRegistryLookup,mRequest.originatingPendingIntent, mRequest.allowBackgroundActivityStart);}} finally {onExecutionComplete();}}

其中,startActivity有三个的重载方法,经过不断的调用,最后会调用:startActivity(final ActivityRecord r, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask, ActivityRecord[] outActivity, boolean restrictedBgActivity) 方法:

 private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,ActivityRecord[] outActivity, boolean restrictedBgActivity) {try {mService.mWindowManager.deferSurfaceLayout();result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,startFlags, doResume, options, inTask, outActivity, restrictedBgActivity);} }

大致的流程图如下:
在这里插入图片描述

接下来就是Launcher进程和Activity的创建了,这个过程和普通的应用启动就没什么区别了,详情查看Android Activity的创建流程。

相关文章:

Android 系统启动过程纪要(基于Android 10)

前言 看过源码的都知道&#xff0c;Launcher系统启动都会经过这三个进程 init ->zygote -> system_server。今天我们就来讲解一下这三个进程以及Launcher系统启动。 init进程 准备Android虚拟机环境&#xff1a;创建和挂载系统文件目录&#xff1b;初始化属性服务&…...

【Docker实用篇】一文入门Docker(4)Docker-Compose

目录 1.Docker-Compose 1.1.初识DockerCompose 1.2.安装DockerCompose 1.2.1 修改文件权限 1.2.2 Base自动补全命令&#xff1a; 1.3部署微服务集群 1.3.1.compose文件 1.3.2.修改微服务配置 1.3.3.打包 1.3.4.拷贝jar包到部署目录 1.3.5.部署 1.Docker-Compose Doc…...

neo4j 图数据库 py2neo 操作 示例代码

文章目录 摘要前置NodeMatcher & RelationshipMatcher创建节点查询获取节点节点有则查询&#xff0c;无则创建创建关系查询关系关系有则查询&#xff0c;无则创建 Cypher语句创建节点 摘要 利用py2neo包&#xff0c;实现把excel表里面的数据&#xff0c;插入到neo4j 图数据…...

从uptime看linux平均负载

从前遇到系统卡顿只会top。。top看不出来怎么搞呢&#xff1f; Linux系统提供了丰富的命令行工具&#xff0c;以帮助用户和系统管理员监控和分析系统性能。在这些工具中&#xff0c;uptime、mpstat和pidstat是非常有用的命令&#xff0c;它们可以帮助你理解系统的平均负载以及资…...

经典数据库练习题及答案

数据表介绍 --1.学生表 Student(SId,Sname,Sage,Ssex) --SId 学生编号,Sname 学生姓名,Sage 出生年月,Ssex 学生性别 --2.课程表 Course(CId,Cname,TId) --CId 课程编号,Cname 课程名称,TId 教师编号 --3.教师表 Teacher(TId,Tname) --TId 教师编号,Tname 教师姓名 --4.成绩…...

架构篇06-复杂度来源:可扩展性

文章目录 预测变化应对变化小结 复杂度来源前面已经讲了高性能和高可用&#xff0c;今天来聊聊可扩展性。 可扩展性指系统为了应对将来需求变化而提供的一种扩展能力&#xff0c;当有新的需求出现时&#xff0c;系统不需要或者仅需要少量修改就可以支持&#xff0c;无须整个系…...

flowable流程结束触发监听器 flowable获取结束节点 flowable流程结束事件响应监听器

flowable流程结束触发监听器 | flowable流程结束获取结束节点 | flowable流程结束事件响应监听器 下面代码是该监听器是对每个到达结束事件后执行的。 原本的流程定义是如果其中任意某个节点进行了驳回&#xff0c;则直接结束流程。 所以在每个节点的驳回对应的排他网关都设…...

【Python3】【力扣题】389. 找不同

【力扣题】题目描述&#xff1a; 【Python3】代码&#xff1a; 1、解题思路&#xff1a;使用计数器分别统计字符串中的元素和出现次数&#xff0c;两个计数器相减&#xff0c;结果就是新添加的元素。 知识点&#xff1a;collections.Counter(...)&#xff1a;字典子类&#x…...

【从0上手cornerstone3D】如何加载nifti格式的文件

在线演示 支持加载的文件格式 .nii .nii.gz 代码实现 npm install cornerstonejs/nifti-volume-loader// ------------- 核心代码 Start------------------- // 注册一个nifti格式的加载器 volumeLoader.registerVolumeLoader("nifti",cornerstoneNiftiImageVolu…...

c# 学习笔记 - 异步编程

文章目录 1. 异步编程介绍1.1 简单介绍1.2 async/await 使用1.3 Task/Task<TResult> 对象 2. 样例2.1 迅速启动所有任务&#xff0c;仅当需要结果才等待任务执行2.2 使用 await 调用异步方法&#xff0c;即使这个异步方法内有 await 也不会同时执行回调和向下执行操作(必…...

设置了uni.chooseLocation,小程序中打不开

设置了uni.chooseLocation&#xff0c;在小程序打不开&#xff0c;点击没反应&#xff0c;地图显现不出来&#xff1b; 解决方案&#xff1a; 1.Hbuilder——微信开发者工具路径没有配置 打开工具——>设置 2.微信小程序服务端口没有开 解决方法&#xff1a;打开微信开发…...

spring retry 配置及使用

spring retry 配置及使用 接口或功能因外界异常导致失败后进行重推机制 依赖 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.1.RELEASE</version></p…...

uni-app的组件(二)

多项选择器checkbox-group 多项选择器&#xff0c;内部由多个 checkbox 组成。 <checkbox-group><checkbox checked color"red" value"1"></checkbox> 篮球<!-- disabled:是否禁用 --><checkbox disabled color"rgba(0,0…...

项目开发中安全问题以及解决办法——客户传进来的数据不可信

用户传进来的数据是不可信的&#xff0c;比如下面这种情况下&#xff1a; PostMapping("/order") public void wrong(RequestBody Order order) { this.createOrder(order); } Data public class Order { private long itemId; //商品ID private BigDecimal ite…...

解决springboot启动报Failed to start bean ‘subProtocolWebSocketHandler‘;

解决springboot启动报 Failed to start bean subProtocolWebSocketHandler; nested exception is java.lang.IllegalArgumentException: No handlers 问题发现问题解决 问题发现 使用springboot整合websocket&#xff0c;启动时报错&#xff0c;示例代码&#xff1a; EnableW…...

什么是技术架构?架构和框架之间的区别是什么?怎样去做好架构设计?(一)

什么是技术架构?架构和框架之间的区别是什么?怎样去做好架构设计?(一)。 在软件行业,对于什么是架构,都有很多的争论,每个人都有自己的理解。在不同的书籍上, 不同的作者, 对于架构的定义也不统一, 角度不同, 定义不同。 一、架构是什么 Linux 有架构,MySQL 有架构,J…...

【多线程】认识Thread类及其常用方法

&#x1f4c4;前言&#xff1a; 本文是对以往多线程学习中 Thread类 的介绍&#xff0c;以及对其中的部分细节问题进行总结。 文章目录 一. 线程的 创建和启动&#x1f346;1. 通过继承 Thread 类创建线程&#x1f345;2. 通过实现 Runnable 接口创建线程&#x1f966;3. 其他方…...

多用户商业版 whisper 2.1在线搭建教程

1. 准备工作 购买许可证&#xff1a;确保你已经购买了足够数量的用户许可证&#xff0c;以便所有员工或客户都能使用软件。系统要求&#xff1a;检查你的服务器和客户端计算机是否满足软件的最低系统要求。网络配置&#xff1a;确保你的网络环境&#xff08;如防火墙、路由器等…...

HEXO搭建个人博客

Hexo是一款基于Node.js的静态博客框架&#xff0c;可以生成静态网页托管在GitHub上。中文文档见HEXO 配置环境 安装Git&#xff1a;下载并安装Git 检查git是否正确安装&#xff1a; git --version 安装Node.js&#xff1a;Node.js 为大多数平台提供了官方的安装程序。注意安装…...

Spring MVC学习之——RequestMapping注解

RequestMapping注解 作用 用于建立请求URL和处理请求方法之间的对应关系。 属性 value&#xff1a;指定请求的实际地址&#xff0c;可以是一个字符串或者一个字符串列表。 value可以不写&#xff0c;直接在括号中写&#xff0c;默认就是value值 RequestMapping(value“/hel…...

云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?

大家好&#xff0c;欢迎来到《云原生核心技术》系列的第七篇&#xff01; 在上一篇&#xff0c;我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在&#xff0c;我们就像一个拥有了一块崭新数字土地的农场主&#xff0c;是时…...

地震勘探——干扰波识别、井中地震时距曲线特点

目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波&#xff1a;可以用来解决所提出的地质任务的波&#xff1b;干扰波&#xff1a;所有妨碍辨认、追踪有效波的其他波。 地震勘探中&#xff0c;有效波和干扰波是相对的。例如&#xff0c;在反射波…...

C++实现分布式网络通信框架RPC(3)--rpc调用端

目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中&#xff0c;我们已经大致实现了rpc服务端的各项功能代…...

C++_核心编程_多态案例二-制作饮品

#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为&#xff1a;煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例&#xff0c;提供抽象制作饮品基类&#xff0c;提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

51c自动驾驶~合集58

我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留&#xff0c;CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制&#xff08;CCA-Attention&#xff09;&#xff0c;…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望

文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例&#xff1a;使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例&#xff1a;使用OpenAI GPT-3进…...

拉力测试cuda pytorch 把 4070显卡拉满

import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试&#xff0c;通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小&#xff0c;增大可提高计算复杂度duration: 测试持续时间&#xff08;秒&…...

Selenium常用函数介绍

目录 一&#xff0c;元素定位 1.1 cssSeector 1.2 xpath 二&#xff0c;操作测试对象 三&#xff0c;窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四&#xff0c;弹窗 五&#xff0c;等待 六&#xff0c;导航 七&#xff0c;文件上传 …...

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)

考察一般的三次多项式&#xff0c;以r为参数&#xff1a; p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]&#xff1b; 此多项式的根为&#xff1a; 尽管看起来这个多项式是特殊的&#xff0c;其实一般的三次多项式都是可以通过线性变换化为这个形式…...

【C++进阶篇】智能指针

C内存管理终极指南&#xff1a;智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...