热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Android系统源码分析Zygote和SystemServer启动过程详解

本文详细解析了Android系统源码中Zygote和SystemServer的启动过程。首先介绍了系统framework层启动的内容,帮助理解四大组件的启动和管理过程。接着介绍了AMS、PMS等系统服务的作用和调用方式。然后详细分析了Zygote的启动过程,解释了Zygote在Android启动过程中的决定作用。最后通过时序图展示了整个过程。

按计划本来从这章开始写四大组件的启动过程的,但是看看源码结构发现为了说的更明白还是先写一点系统framework层启动的内容,帮助理解四大组件的启动以及管理过程。我们知道四大组件管理是通过一些服务以及线程实现的,所以先把一些基本概念弄清楚比较好,比如AMS(ActivityManagerService)、PMS(PackageManagerService)等系统服务的作用以及调用方式,了解这些之后再看四大组件相对容易些,因此我们本章先介绍系统启动、部分系统服务的作用。

Zygote启动过程

Zygote是一个孕育器,Android系统所有的应用进程以及系统服务SystemServer都是有Zygote进程孕育(fork)而生的,因此Zygote在Android启动过程中起着决定作用。Zygote的启动是从它的main函数开始的,因此我们从这个函数开始分析。整个过程看下面的时序图。

《Android系统源码分析--Zygote和SystemServer启动过程》 Zygote.jpg

下面我们开始根据时序图进行分析。

Step 0.ZygoteInit.main

public static void main(String argv[]) {
...
try {
...
registerZygoteSocket(socketName);

...

preload();

...
gcAndFinalize();

...
if (startSystemServer) {
startSystemServer(abiList, socketName);
}
runSelectLoop(abiList);
closeServerSocket();
} catch (MethodAndArgsCaller caller) {
...
} catch (Throwable ex) {
...
}
}

首先调用registerZygoteSocket方法,创建一个socket接口,用来和ActivityManagerService通讯,然后调用preload方法预加载一些资源等;然后调用gcAndFinalize方法释放一些内存;然后调用startSystemServer方法启动SystemServer组件,然后调用runSelectLoop方法,创建一个无限循环,在socket接口上等待ActivityManagerService请求创建新的应用程序进程;最后调用closeServerSocket方法关闭上面创建的socket。

Step 1.ZygoteInit.registerZygoteSocket

private static void registerZygoteSocket(String socketName) {
if (sServerSocket == null) {
int fileDesc;
final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
try {
String env = System.getenv(fullSocketName);
fileDesc = Integer.parseInt(env);
} catch (RuntimeException ex) {
...
}
try {
FileDescriptor fd = new FileDescriptor();
fd.setInt$(fileDesc);
sServerSocket = new LocalServerSocket(fd);
} catch (IOException ex) {
throw new RuntimeException(
"Error binding to local socket '" + fileDesc + "'", ex);
}
}
}

这个sServerSocket是通过传入FileDescriptor(文件描述者)通过new一个来LocalServerSocket创建的。

Step 2.LocalServerSocket

public LocalServerSocket(FileDescriptor fd) throws IOException
{
impl = new LocalSocketImpl(fd);
impl.listen(LISTEN_BACKLOG);
localAddress = impl.getSockAddress();
}

在LocalServerSocket构造函数中又new了一个LocalSocketImpl,然后调用LocalSocketImpl的listen方法,最后通过getSockAddress方法获取LocalSocketAddress对象。

Step 3.LocalSocketImpl

/*package*/ LocalSocketImpl(FileDescriptor fd) throws IOException
{
this.fd = fd;
}

这里只是传入了FileDescriptor(文件描述者)。

Step 5.ZygoteInit.preload

static void preload() {
...
beginIcuCachePinning();
...
preloadClasses();
...
preloadResources();
...
preloadOpenGL();
...
preloadSharedLibraries();
preloadTextResources();
...
}

这里主要是预加载,1.预加载ICU缓存,2.执行Zygote进程初始化,预加载一些普通类,3.预加载mResources,4.预加载OpenGL,5.预加载共享库,6.预加载TextView的字体缓存。

Step 12.ZygoteInit.gcAndFinalize

/*package*/ static void gcAndFinalize() {
final VMRuntime runtime = VMRuntime.getRuntime();
...
System.gc();
runtime.runFinalizationSync();
System.gc();
}

这里主要是调用System.gc来释放一部分内存。

Step 13.ZygoteInit.startSystemServer

private static boolean startSystemServer(String abiList, String socketName)
throws MethodAndArgsCaller, RuntimeException {
...
int pid;
try {
...
/* Request to fork the system server process */
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.debugFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
} catch (IllegalArgumentException ex) {
...
}
/* For child process */
if (pid == 0) {
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}
handleSystemServerProcess(parsedArgs);
}
return true;
}

首先Zygote会通过调用Zygote.forkSystemServer方法来创建一个新的进程来启动SystemServer,并且返回这个进程的pid,如果pid为0,并且有另外一个Zygote则会执行waitForSecondaryZygote关闭另外的Zygote进程,然后调用handleSystemServerProcess方法。

Step 16.ZygoteInit.handleSystemServerProcess

private static void handleSystemServerProcess(
ZygoteConnection.Arguments parsedArgs)
throws ZygoteInit.MethodAndArgsCaller {
closeServerSocket();
...
final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
if (systemServerClasspath != null) {
performSystemServerDexOpt(systemServerClasspath);
}
if (parsedArgs.invokeWith != null) {
...
} else {
...
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
}
}

首先调用closeServerSocket方法关闭socket,然后调用performSystemServerDexOpt来创建安装连接InstallerConnection,最后调用RuntimeInit.zygoteInit方法。

Step 19.RuntimeInit.zygoteInit

public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
...
nativeZygoteInit();
applicationInit(targetSdkVersion, argv, classLoader);
}

首先调用nativeZygoteInit函数来执行一个Binder进程间通讯机制初始化工作,然后就可以在进程间进行通讯了,然后执行applicationInit方法。

Step 21.RuntimeInit.applicationInit

private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
...
invokeStaticMain(args.startClass, args.startArgs, classLoader);
}

这里主要是执行一个invokeStaticMain方法来调用SystemServer的main方法。

Step 24.ZygoteInit.runSelectLoop

private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
ArrayList fds = new ArrayList();
ArrayList peers = new ArrayList();
fds.add(sServerSocket.getFileDescriptor());
peers.add(null);
while (true) {
...
try {
Os.poll(pollFds, -1);
} catch (ErrnoException ex) {
...
}
for (int i = pollFds.length - 1; i >= 0; --i) {
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
if (i == 0) {
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
boolean dOne= peers.get(i).runOnce();
if (done) {
peers.remove(i);
fds.remove(i);
}
}
}
}
}

这里通过acceptCommandPeer来创建ActivityManagerService与Socket的连接,然后调用ZygoteConnection.runOnce方法来创建新的应用程序。

SystemServer启动过程

我们从上面的Step 13 知道了SystemServer的main函数调用位置,下面我们分析一下SystemServer的启动过程。

《Android系统源码分析--Zygote和SystemServer启动过程》 SystemServer.jpg

在main方法中new了一个SystemServer然后调用它的run方法:

private void run() {
try {
...
// Mmmmmm... more memory!
// 清除vm内存增长上限,由于启动过程需要较多的虚拟机内存空间
VMRuntime.getRuntime().clearGrowthLimit();
// The system server has to run all of the time, so it needs to be
// as efficient as possible with its memory usage.
// 设置内存的可能有效使用率为0.8
VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
// Some devices rely on runtime fingerprint generation, so make sure
// we've defined it before booting further.
Build.ensureFingerprintProperty();
// Within the system server, it is an error to access Environment paths without
// explicitly specifying a user.
// 访问环境变量前,需要明确地指定用户
Environment.setUserRequired(true);
// Within the system server, any incoming Bundles should be defused
// to avoid throwing BadParcelableException.
BaseBundle.setShouldDefuse(true);
// Ensure binder calls into the system always run at foreground priority.
// 确保当前系统进程的binder调用,总是运行在前台优先级(foreground priority)
BinderInternal.disableBackgroundScheduling(true);
// Increase the number of binder threads in system_server
BinderInternal.setMaxThreads(sMaxBinderThreads);
...
// 准备主线程的Looper
Looper.prepareMainLooper();
// Initialize native services.
// 加载android_servers.so库,该库包含的源码在frameworks/base/services/目录下
System.loadLibrary("android_servers");
// Check whether we failed to shut down last time we tried.
// This call may not return.
performPendingShutdown();
// Initialize the system context.
// 初始化系统上下文
createSystemContext();
// Create the system service manager.
mSystemServiceManager = new SystemServiceManager(mSystemContext);
//将mSystemServiceManager添加到本地服务的成员sLocalServiceObjects
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
} finally {
...
}
// Start services.
try {
...
startBootstrapServices(); // 启动引导服务
startCoreServices(); // 启动核心服务
startOtherServices(); // 启动其他服务
} catch (Throwable ex) {
...
} finally {
...
}
...
// Loop(循环) forever.
Looper.loop();
...
}

Step 3.Build.ensureFingerprintProperty

public static void ensureFingerprintProperty() {
if (TextUtils.isEmpty(SystemProperties.get("ro.build.fingerprint"))) {
try {
SystemProperties.set("ro.build.fingerprint", FINGERPRINT);
} catch (IllegalArgumentException e) {
Slog.e(TAG, "Failed to set fingerprint property", e);
}
}
}

确认设备的指纹属性。

Step 7.Looper.prepareMainLooper()

public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}

准备main looper,这个详细的过程我们下一章再讲,这里先看一下流程。

Step 10.SystemServer.performPendingShutdown

private void performPendingShutdown() {
final String shutdownAction = SystemProperties.get(
ShutdownThread.SHUTDOWN_ACTION_PROPERTY, "");
if (shutdownAction != null && shutdownAction.length() > 0) {
// 是否重启
boolean reboot = (shutdownAction.charAt(0) == '1');
final String reason;
if (shutdownAction.length() > 1) {
reason = shutdownAction.substring(1, shutdownAction.length());
} else {
reason = null;
}
if (PowerManager.REBOOT_RECOVERY_UPDATE.equals(reason)) {
File packageFile = new File(UNCRYPT_PACKAGE_FILE);
if (packageFile.exists()) {
String filename = null;
try {
filename = FileUtils.readTextFile(packageFile, 0, null);
} catch (IOException e) {
Slog.e(TAG, "Error reading uncrypt package file", e);
}
if (filename != null && filename.startsWith("/data")) {
if (!new File(BLOCK_MAP_FILE).exists()) {
...
return;
}
}
}
}
ShutdownThread.rebootOrShutdown(null, reboot, reason);
}
}

这里主要是通过关机的action来判断是否重启或者关机。

Step 13.SystemServer.createSystemContext

private void createSystemContext() {
// 初始化ActivityThread,并设置默认主题
ActivityThread activityThread = ActivityThread.systemMain();
mSystemCOntext= activityThread.getSystemContext();
mSystemContext.setTheme(DEFAULT_SYSTEM_THEME);
}

首先调用ActivityThread.systemMain方法创建ActivityThread对象然后获取mSystemContext,并且设置默认系统主题。

Step 15.ActivityThread.systemMain

public static ActivityThread systemMain() {
...
ActivityThread thread = new ActivityThread();
thread.attach(true);
return thread;
}

创建ActivityThread对象,并调用attach方法。

Step 17.ResourcesManager.getInstance

public static ResourcesManager getInstance() {
synchronized (ResourcesManager.class) {
if (sResourcesManager == null) {
sResourcesManager = new ResourcesManager();
}
return sResourcesManager;
}

单例模式创建ResourcesManager对象并且返回。

Step 19.ActivityThread.attach

private void attach(boolean system) {
sCurrentActivityThread = this;
mSystemThread = system;
if (!system) {
...
} else {
...
try {
mInstrumentation = new Instrumentation();
ContextImpl cOntext= ContextImpl.createAppContext(
this, getSystemContext().mPackageInfo);
mInitialApplication = context.mPackageInfo.makeApplication(true, null);
mInitialApplication.onCreate();
} catch (Exception e) {
...
}
}
...
}

因为参数传入的是true,表明是系统的线程,所以执行else里面的内容,首先创建Instrumentation,然后调用ContextImpl.createAppContext方法创建ContextImpl,然后通过调用LoadedApk.makeApplication方法创建Application,然后调用Application.onCreate方法。

Step 22.ContextImpl.createAppContext

static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
return new ContextImpl(null, mainThread,
packageInfo, null, null, 0, null, null, Display.INVALID_DISPLAY);
}

通过new ContextImpl来创建ContextImpl对象。

Step 22.LoadedApk.makeApplication

public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
...
Application app = null;
...
try {
...
ContextImpl appCOntext= ContextImpl.createAppContext(mActivityThread, this);
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app);
} catch (Exception e) {
...
}
...
if (instrumentation != null) {
try {
instrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
...
}
}
...
return app;
}

通过ContextImpl.createAppContext方法创建ContextImpl对象,然后调用mActivityThread.mInstrumentation.newApplication方法创建Application对象,然后调用instrumentation.callApplicationOnCreate方法。

Step 23.ContextImpl.createAppContext

static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
return new ContextImpl(null, mainThread,
packageInfo, null, null, 0, null, null, Display.INVALID_DISPLAY);
}

创建ContextImpl对象并返回。

Step 26.Instrumentation.createAppContext

public Application newApplication(ClassLoader cl, String className, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
return newApplication(cl.loadClass(className), context);
}

这里主要是调用newApplication方法返回Application。

Step 28.Instrumentation.newApplication

static public Application newApplication(Class clazz, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
Application app = (Application)clazz.newInstance();
app.attach(context);
return app;
}

调用class.newInstance方法创建Application,然后调用Application.attach方法,向Application中传入context。

Step 32.Application.attach

/* package */ final void attach(Context context) {
attachBaseContext(context);
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}

通过ContextImpl.getImpl方法获取LoadedApk对象。

Step 34.Instrumentation.callApplicationOnCreate

public void callApplicationOnCreate(Application app) {
app.onCreate();
}

这里开始调用Application的onCreate方法。

Step 39.ActivityThread.getSystemContext

public ContextImpl getSystemContext() {
synchronized (this) {
if (mSystemCOntext== null) {
mSystemCOntext= ContextImpl.createSystemContext(this);
}
return mSystemContext;
}
}

通过ContextImpl.createSystemContext创建mSystemContext。

Step 40.ContextImpl.createSystemContext

static ContextImpl createSystemContext(ActivityThread mainThread) {
LoadedApk packageInfo = new LoadedApk(mainThread);
ContextImpl cOntext= new ContextImpl(null, mainThread,
packageInfo, null, null, 0, null, null, Display.INVALID_DISPLAY);
context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(),
context.mResourcesManager.getDisplayMetrics());
return context;
}

创建ContextImpl并且返回。

Step 43.SystemServer.startBootstrapServices

private void startBootstrapServices() {
...
// 安装服务
Installer installer = mSystemServiceManager.startService(Installer.class);
// Activity管理服务
mActivityManagerService = mSystemServiceManager.startService(
ActivityManagerService.Lifecycle.class).getService();
mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
mActivityManagerService.setInstaller(installer);
...
// 电量管理服务
mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
...
// 管理LEDs和背光灯服务
mSystemServiceManager.startService(LightsService.class);
// 显示管理服务
mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);
mSystemServiceManager.startBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
// 包管理服务
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
mFirstBoot = mPackageManagerService.isFirstBoot();
mPackageManager = mSystemContext.getPackageManager();
...
// 启动用户管理服务
mSystemServiceManager.startService(UserManagerService.LifeCycle.class);
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
//初始化安装包资源的属性缓存
AttributeCache.init(mSystemContext);
// 启动系统进程的应用实例
mActivityManagerService.setSystemProcess();
// 启动传感器服务
startSensorService();
}

这里主要是启动系统引导服务。

Step 44.SystemServer.startCoreServices

private void startCoreServices() {
// 启动电池服务
mSystemServiceManager.startService(BatteryService.class);
// 启动应用统计服务
mSystemServiceManager.startService(UsageStatsService.class);
mActivityManagerService.setUsageStatsManager(
LocalServices.getService(UsageStatsManagerInternal.class));
// 启动WebView更新服务
mWebViewUpdateService = mSystemServiceManager.startService(WebViewUpdateService.class);
}

启动核心服务。

Step 45.SystemServer.startOtherServices

这里代码就不贴了,都是启动服务的代码,这里有很多服务,我简单列一下服务并说一下服务基本功能。

服务名称服务名称
SchedulingPolicyServiceCameraService
TelecomLoaderServiceAccountManagerService.Lifecycle
ContentService.LifecycleVibratorService
ConsumerIrServiceAlarmManagerService
InputManagerServiceWindowManagerService
VrManagerServicePersistentDataBlockService
MetricsLoggerServiceIpConnectivityMetrics
PinnerServiceInputMethodManagerService.Lifecycle
MountService.LifecycleUiModeManagerService
LockSettingsService.LifecycleBluetoothService
DeviceIdleControllerNsdService
StatusBarManagerServiceClipboardService
NetworkManagementServiceWifiService
NetworkScoreServiceNetworkStatsService
NetworkPolicyManagerServiceWifiNanService
WifiP2pServiceTextServicesManagerService.Lifecycle
WifiScanningServiceConnectivityService
RttServiceDevicePolicyManagerService.Lifecycle
UpdateLockServiceRecoverySystemService
NotificationManagerServiceDeviceStorageMonitorService
LocationManagerServiceCountryDetectorService
SearchManagerService.LifecycleDropBoxManagerService
AudioService.LifecycleDockObserver
ThermalObserverMidiService.Lifecycle
UsbService.LifecycleSerialService
HardwarePropertiesManagerServiceNightDisplayService
JobSchedulerServiceSoundTriggerService
BackupManagerService.LifecycleAppWidgetService
VoiceInteractionManagerServiceGestureLauncherService
SensorNotificationServiceContextHubSystemService
DiskStatsServiceSamplingProfilerService
NetworkTimeUpdateServiceCommonTimeManagementService
EmergencyAffordanceServiceDreamManagerService
AssetAtlasServiceGraphicsStatsService
PrintManagerServiceRestrictionsManagerService
MediaSessionServiceHdmiControlService
TvInputManagerServiceMediaResourceMonitorService
TvRemoteServiceMediaRouterService
TrustManagerServiceFingerprintService
ShortcutService.LifecycleLauncherAppsService
MediaProjectionManagerServiceWearBluetoothService
WearWifiMediatorServiceWearTimeService
MmsServiceBrokerRetailDemoModeService
NsdServiceWallpaperManagerService.Lifecycle

参考:

Android系统启动-SystemServer下篇
Android系统进程Zygote启动过程的源代码分析

Android开发群:192508518

微信公众账号:Code-MX

《Android系统源码分析--Zygote和SystemServer启动过程》

注:本文原创,转载请注明出处,多谢。


推荐阅读
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 本文由编程笔记#小编为大家整理,主要介绍了logistic回归(线性和非线性)相关的知识,包括线性logistic回归的代码和数据集的分布情况。希望对你有一定的参考价值。 ... [详细]
  • 本文介绍了如何使用PHP向系统日历中添加事件的方法,通过使用PHP技术可以实现自动添加事件的功能,从而实现全局通知系统和迅速记录工具的自动化。同时还提到了系统exchange自带的日历具有同步感的特点,以及使用web技术实现自动添加事件的优势。 ... [详细]
  • 本文介绍了在rhel5.5操作系统下搭建网关+LAMP+postfix+dhcp的步骤和配置方法。通过配置dhcp自动分配ip、实现外网访问公司网站、内网收发邮件、内网上网以及SNAT转换等功能。详细介绍了安装dhcp和配置相关文件的步骤,并提供了相关的命令和配置示例。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • 拥抱Android Design Support Library新变化(导航视图、悬浮ActionBar)
    转载请注明明桑AndroidAndroid5.0Loollipop作为Android最重要的版本之一,为我们带来了全新的界面风格和设计语言。看起来很受欢迎࿰ ... [详细]
  • 不同优化算法的比较分析及实验验证
    本文介绍了神经网络优化中常用的优化方法,包括学习率调整和梯度估计修正,并通过实验验证了不同优化算法的效果。实验结果表明,Adam算法在综合考虑学习率调整和梯度估计修正方面表现较好。该研究对于优化神经网络的训练过程具有指导意义。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • Python瓦片图下载、合并、绘图、标记的代码示例
    本文提供了Python瓦片图下载、合并、绘图、标记的代码示例,包括下载代码、多线程下载、图像处理等功能。通过参考geoserver,使用PIL、cv2、numpy、gdal、osr等库实现了瓦片图的下载、合并、绘图和标记功能。代码示例详细介绍了各个功能的实现方法,供读者参考使用。 ... [详细]
author-avatar
mobiledu2502899835
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有