我的编程空间,编程开发者的网络收藏夹
学习永远不晚

怎么用java源代码分析jvm.dll装载过程

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

怎么用java源代码分析jvm.dll装载过程

怎么用java源代码分析jvm.dll装载过程,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。

简述
众所周知java.exe是java class文件的执行程序,但实际上java.exe程序只是
一个执行的外壳,它会装载jvm.dll(windows下,以下皆以windows平台为例,
linux下和solaris下其实类似,为:libjvm.so),这个动态连接库才是java
虚拟机的实际操作处理所在。本文探究java.exe程序是如何查找和装载jvm.dll
动态库,并调用它进行class文件执行处理的。

源代码
主要分析的源代码为:
j2seclass="lazy" data-srcshareinjava.c
j2seclass="lazy" data-srcwindowsinjava_md.c

java.c是什么东西
‘java程序’源代码
所谓‘java程序’,包括jdk中的java.exejavac.exejavadoc.exe,java.c源
代码中通过JAVA_ARGS宏来控制生成的代码,如果该宏没定义则编译文件控制生
成java.exe否则编译文件控制生成其他的‘java程序’。
比如:
j2semakejavajavacMakefile(这是javac编译文件)中:
$(CD) ../../sun/javac ; $(MAKE) $@ RELEASE=$(RELEASE) FULL_VERSION=$(FULL_VERSION)
j2semakesunjavacjavacMakefile(由上面Makefile文件调用)中:
JAVA_ARGS = "{ "-J-ms8m", "com.sun.tools.javac.Main" }"
则由同一份java.c代码生成的javac.exe程序就会直接调用java类方法:
com.sun.tools.javac.Main,这样使其执行起来就像是直接运行的一个exe文件,
而未定义JAVA_ARGS的java.exe程序则会调用传递过来参数中的类方法。

从java.c的main入口函数说起
main()函数中前面一段为重新分配参数指针的处理。
然后调用函数:CreateExecutionEnvironment,该函数主要查找java运行环境的
目录,和jvm.dll这个虚拟机核心动态连接库文件路径所在。根据操作系统不同,
该函数有不同实现版本,但大体处理逻辑相同,我们看看windows平台该函数的处
理(j2seclass="lazy" data-srcwindowsinjava_md.c)。

CreateExecutionEnvironment函数主要分为三步处理:
a、查找jre路径。
b、装载jvm.cfg中指定的虚拟机动态连接库(jvm.dll)参数。
c、取jvm.dll文件路径。

实现:
a、查找jre路径是通过java_md.c中函数:GetJREPath实现的。
该函数首先调用GetApplicationHome函数,GetApplicationHome函数调用windows
API函数GetModuleFileName取java.exe程序的绝对路径,以我的jdk安装路径为例,
为:“D:javaj2sdk1.4.2_04injava.exe”,然后去掉文件名取绝对路径为:
“D:javaj2sdk1.4.2_04in”,之后会在去掉最后一级目录,现在绝对路径为:
“D:javaj2sdk1.4.2_04”。
然后GetJREPath函数继续判断刚刚取的路径+injava.dll组合成的这个java.dll
文件是否存在,如果存在则“D:javaj2sdk1.4.2_04”为JRE路径,否则判断取得
的“D:javaj2sdk1.4.2_04”路径+jreinjava.dll文件是否存在,存在则
“D:javaj2sdk1.4.2_04jre”为JRE路径。如果上面两种情况都不存在,则从注
册表中去查找(参见函数GetPublicJREHome)。

函数:GetPublicJREHome先查找
HKEY_LOCAL_MACHINESoftwareJavaSoftJava Runtime EnvironmentCurrentVersion
键值“当前JRE版本号”,判断“当前JRE版本号”是否为1.4做为版本号,如果是则
取HKEY_LOCAL_MACHINESoftwareJavaSoftJava Runtime Environment“当前JRE版本号”
JavaHome的路径所在为JRE路径。

我的JDK返回的JRE路径为:“D:javaj2sdk1.4.2_04jre”。

b、装载jvm.cfg虚拟机动态连接库配置文件是通过java.c中函数:ReadKnownVMs实现
的。
该函数首先组合jvm.cfg文件的绝对路径,JRE路径+lib+ARCH(CPU构架)+jvm.cfg
ARCH(CPU构架)的判断是通过java_md.c中GetArch函数判断的,该函数中windows平
台只有两种情况:WIN64的‘ia64’,其他情况都为‘i386’。我的为i386所以jvm.cfg
文件绝对路径为:“D:javaj2sdk1.4.2_04jrelibi386jvm.cfg”。文件内容如
下:

## @(#)jvm.cfg   1.7 03/01/23# # Copyright 2003 Sun Microsystems, Inc. All rights reserved.# SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.# # ### List of JVMs that can be used as an option to java, javac, etc.# Order is important -- first in this list is the default JVM.# NOTE that this both this file and its format are UNSUPPORTED and# WILL GO AWAY in a future release.## You may also select a JVM in an arbitrary location with the# "-XXaltjvm=

" option, but that too is unsupported# and may not be available in a future release.#-client KNOWN-server KNOWN-hotspot ALIASED_TO -client-classic WARN-native ERROR-green ERROR


(如果细心的话,我们会发现在JDK目录中我的为:“D:javaj2sdk1.4.2_04jreinclient”和“D:javaj2sdk1.4.2_04jreinserver”两个目录下都存在jvm.dll文件。而java正是通过jvm.cfg配置文件来管理这些不同版本的jvm.dll的。)

ReadKnownVMs函数会将该文件中的配置内容读入到一个JVM配置结构的全局变量中,该函数首先跳过注释(以‘#’开始的行),然后读取以‘-’开始的行指定的jvm参数,每一行为一个jvm信息,第一部分为jvm虚拟机名称,第二部分为配置参数,比如行:
“-client KNOWN”则“-client”为虚拟机名称,而“KNOWN”为配置类型参数,“KNOWN”
表示该虚拟机的jvm.dll存在,而“ALIASED_TO”表示为另一个jvm.dll的别名,“WARN”
表示该虚拟机的jvm.dll不存在但运行时会用其他存在的jvm.dll替代执行,而“ERROR”
同样表示该类虚拟机的jvm.dll不存在且运行时不会找存在的jvm.dll替代而直接抛出错误
信息。

在运行java程序时指定使用那个虚拟机的判断是由java.c中函数:CheckJvmType判断,该函数会检查java运行参数中是否有指定jvm的参数,然后从ReadKnownVMs函数读取的jvm.cfg数据结构中去查找,从而指定不同的jvm类型(最终导致装载不同jvm.dll)。有两种方法可以指定jvm类型,一种按照jvm.cfg文件中的jvm名称指定,第二种方法是直接指定,它们执行的方法分别是“java -J”、“java -XXaltjvm=”或“java -J-XXaltjvm=”。如果是第一种参数传递方式,CheckJvmType函数会取参数‘-J’后面的jvm名称,然后从已知的jvm配置参数中查找如果找到同名的则去掉该jvm名称前的‘-’直接返回该值;而第二种方法,会直接返回“-XXaltjvm=”或“-J-XXaltjvm=”后面的jvm类型名称;如果在运行java时未指定上面两种方法中的任一一种参数,CheckJvmType会取配置文件中第一个配置中的jvm名称,去掉名称前面的‘-’返回该值。CheckJvmType函数的这个返回值会在下面的函数中汇同jre路径组合成jvm.dll的绝对路径。

比如:如果在运行java程序时使用“java -J-client test”则ReadKnownVMs会读取参数“-client”然后查找jvm.cfg读入的参数中是否有jvm名称为“-client”的,如果有则去掉jvm名称前的“-”直接返回“client”;而如果在运行java程序时使用如下参数:
“java -XXaltjvm=D:javaj2sdk1.4.2_04jreinclient test”,则ReadKnownVMs
会直接返回“D:javaj2sdk1.4.2_04jreinclient”;如果不带上面参数执行如:
“java test”,因为在jvm.cfg配置文件中第一个存在的jvm为“-client”,所以函数
ReadKnownVMs也会去掉jvm名称前的“-”返回“client”。其实这三中情况都是使用的
“D:javaj2sdk1.4.2_04jreinclientjvm.dll”这个jvm动态连接库处理test这个class的,见下面GetJVMPath函数。

c、取jvm.dll文件路径是通过java_md.c中函数:GetJVMPath实现的。
由上面两步我们已经获得了JRE路径和jvm的类型字符串。GetJVMPath函数判断CheckJvmType
返回的jvm类型字符串中是否包含了‘’或‘/’如果包含则以该jvm类型字符串+jvm.dll作为JVM的全路径,否则以JRE路径+in+jvm类型字符串+jvm.dll作为JVM的全路径。

看看上面的例子,第一种情况“java -J-client test”jvm.dll路径为:
JRE路径+in+jvm类型字符串+jvm.dll 按照我的JDK路径则为:
“D:javaj2sdk1.4.2_04jre”+“in”+“client”+“jvm.dll”。
第二种情况“java -XXaltjvm=D:javaj2sdk1.4.2_04jreinclient test”路径为:
jvm类型字符串+jvm.dll即为:“D:javaj2sdk1.4.2_04jreinclient”+“jvm.dll”
第三种情况“java test”为:“D:javaj2sdk1.4.2_04jre”+“in”+“client”
+“jvm.dll”与情况一相同。所以这三种情况都是调用的jvm动态连接库“D:java
j2sdk1.4.2_04jreinclientjvm.dll”处理test类的。

我们来进一步验证一下:
打开cmd控制台:

设置java装载调试
E:workjava_research>set _JAVA_LAUNCHER_DEBUG=1
情况一
E:workjava_research>java -J-client test.ScanDirectory
----_JAVA_LAUNCHER_DEBUG----
JRE path is D:javaj2sdk1.4.2_04jre
jvm.cfg[0] = ->-client<-
jvm.cfg[1] = ->-server<-
jvm.cfg[2] = ->-hotspot<-
jvm.cfg[3] = ->-classic<-
jvm.cfg[4] = ->-native<-
jvm.cfg[5] = ->-green<-
299 micro seconds to parse jvm.cfg
JVM path is D:javaj2sdk1.4.2_04jreinclientjvm.dll
2897 micro seconds to LoadJavaVM
JavaVM args:
version 0x00010002, ignoreUnrecognized is JNI_FALSE, nOptions is 2
option[ 0] = '-Djava.class.path=.'
option[ 1] = '-Dsun.java.command=test.ScanDirectory'
50001 micro seconds to InitializeJVM
Main-Class is 'test.ScanDirectory'
Apps' argc is 0
10208 micro seconds to load main class
----_JAVA_LAUNCHER_DEBUG----
usage: java test.ScanDirectory DIR [output file]
情况二
E:workjava_research>java -XXaltjvm=D:javaj2sdk1.4.2_04jreinclient test.ScanDirectory
----_JAVA_LAUNCHER_DEBUG----
JRE path is D:javaj2sdk1.4.2_04jre
jvm.cfg[0] = ->-client<-
jvm.cfg[1] = ->-server<-
jvm.cfg[2] = ->-hotspot<-
jvm.cfg[3] = ->-classic<-
jvm.cfg[4] = ->-native<-
jvm.cfg[5] = ->-green<-
386 micro seconds to parse jvm.cfg
JVM path is D:javaj2sdk1.4.2_04jreinclientjvm.dll
2795 micro seconds to LoadJavaVM
JavaVM args:
version 0x00010002, ignoreUnrecognized is JNI_FALSE, nOptions is 2
option[ 0] = '-Djava.class.path=.'
option[ 1] = '-Dsun.java.command=test.ScanDirectory'
49978 micro seconds to InitializeJVM
Main-Class is 'test.ScanDirectory'
Apps' argc is 0
9598 micro seconds to load main class
----_JAVA_LAUNCHER_DEBUG----
usage: java test.ScanDirectory DIR [output file]
情况三
E:workjava_research>java test.ScanDirectory
----_JAVA_LAUNCHER_DEBUG----
JRE path is D:javaj2sdk1.4.2_04jre
jvm.cfg[0] = ->-client<-
jvm.cfg[1] = ->-server<-
jvm.cfg[2] = ->-hotspot<-
jvm.cfg[3] = ->-classic<-
jvm.cfg[4] = ->-native<-
jvm.cfg[5] = ->-green<-
381 micro seconds to parse jvm.cfg
JVM path is D:javaj2sdk1.4.2_04jreinclientjvm.dll
3038 micro seconds to LoadJavaVM
JavaVM args:
version 0x00010002, ignoreUnrecognized is JNI_FALSE, nOptions is 2
option[ 0] = '-Djava.class.path=.'
option[ 1] = '-Dsun.java.command=test.ScanDirectory'
50080 micro seconds to InitializeJVM
Main-Class is 'test.ScanDirectory'
Apps' argc is 0
10215 micro seconds to load main class
----_JAVA_LAUNCHER_DEBUG----
usage: java test.ScanDirectory DIR [output file]
三个的JVM路径都为:
JVM path is D:javaj2sdk1.4.2_04jreinclientjvm.dll

其他情况
E:workjava_research>java -J-server test.ScanDirectory
----_JAVA_LAUNCHER_DEBUG----
JRE path is D:javaj2sdk1.4.2_04jre
jvm.cfg[0] = ->-client<-
jvm.cfg[1] = ->-server<-
jvm.cfg[2] = ->-hotspot<-
jvm.cfg[3] = ->-classic<-
jvm.cfg[4] = ->-native<-
jvm.cfg[5] = ->-green<-
377 micro seconds to parse jvm.cfg
JVM path is D:javaj2sdk1.4.2_04jreinserverjvm.dll
2985 micro seconds to LoadJavaVM
JavaVM args:
version 0x00010002, ignoreUnrecognized is JNI_FALSE, nOptions is 2
option[ 0] = '-Djava.class.path=.'
option[ 1] = '-Dsun.java.command=test.ScanDirectory'
62382 micro seconds to InitializeJVM
Main-Class is 'test.ScanDirectory'
Apps' argc is 0
12413 micro seconds to load main class
----_JAVA_LAUNCHER_DEBUG----
usage: java test.ScanDirectory DIR [output file]
E:workjava_research>java -XXaltjvm=D:javaj2sdk1.4.2_04jreinserver test.ScanDirectory
----_JAVA_LAUNCHER_DEBUG----
JRE path is D:javaj2sdk1.4.2_04jre
jvm.cfg[0] = ->-client<-
jvm.cfg[1] = ->-server<-
jvm.cfg[2] = ->-hotspot<-
jvm.cfg[3] = ->-classic<-
jvm.cfg[4] = ->-native<-
jvm.cfg[5] = ->-green<-
376 micro seconds to parse jvm.cfg
JVM path is D:javaj2sdk1.4.2_04jreinserverjvm.dll
2937 micro seconds to LoadJavaVM
JavaVM args:
version 0x00010002, ignoreUnrecognized is JNI_FALSE, nOptions is 2
option[ 0] = '-Djava.class.path=.'
option[ 1] = '-Dsun.java.command=test.ScanDirectory'
62725 micro seconds to InitializeJVM
Main-Class is 'test.ScanDirectory'
Apps' argc is 0
8942 micro seconds to load main class
----_JAVA_LAUNCHER_DEBUG----
usage: java test.ScanDirectory DIR [output file]

由上面可以看出,如果我们安装了多个jdk或jre版本的话,使用“java -XXaltjvm=”
可以通过绝对路径指定到其他版本的jvm.dll上去,至于能不能运行还有待测试。

我们下面回到java.c的main函数中看看上面找到的jvm.dll是如何装载挂接执行的。

该操作大致分为三步:
a、装载jvm.dll动态连接库。
b、初始化jvm.dll并挂接到JNIEnv(JNI调用接口)实例。
c、调用JNIEnv实例装载并处理class类。

实现:
a、装载jvm.dll动态连接库是由main函数调用java_md.c中LoadJavaVM函数实现的。
main函数首先构造了一个InvocationFunctions结构的局部变量,InvocationFunctions
结构有两个函数指针:

typedef struct {    CreateJavaVM_t CreateJavaVM;    GetDefaultJavaVMInitArgs_t GetDefaultJavaVMInitArgs;} InvocationFunctions;

函数LoadJavaVM中先调用windows API函数:LoadLibrary装载jvm.dll动态连接库,
之后将jvm.dll中的导出函数JNI_CreateJavaVM和JNI_GetDefaultJavaVMInitArgs
挂接到InvocationFunctions变量的CreateJavaVM和GetDefaultJavaVMInitArgs函数
指针变量上。jvm.dll的装载工作宣告完成。

b、初始化jvm.dll并挂接到JNIEnv(JNI调用接口)实例是通过java.c中函数:
InitializeJVM完成的。
main方法中首先定义了一个JNIEnv结构的指针,JNIEnv结构中定义了许多与装载class
类文件、查找类方法、调用类方法有关的函数指针变量。InitializeJVM会调用上面
以挂接jvm.dll中JNI_CreateJavaVM的InvocationFunctions结构变量的CreateJavaVM方法,即调用jvm.dll中函数JNI_CreateJavaVM,该函数会将JNIEnv结构的实例返回到main中的JNIEnv结构的指针上。这样main中的JNIEnv指针获取了JNIEnv实例后,就可以开始对class文件进行处理了。

c、调用JNIEnv实例装载并处理class类。
a)如果是执行jar包。
如果执行的是一个jar包的话,main函数会调用java.c中的函数:GetMainClassName,该函数使用JNIEnv实例构造并调用java类:java.util.jar.JarFile中方法getManifest()并从返回的Manifest对象中取getAttributes("Main-Class")的值,即jar包中文件:
META-INF/MANIFEST.MF指定的Main-Class的主类名作为运行的主类。
之后main函数会调用java.c中LoadClass方法装载该主类(使用JNIEnv实例的FindClass)。
b)如果是执行class方法。
main函数直接调用java.c中LoadClass方法装载该类。

然后main函数调用JNIEnv实例的GetStaticMethodID方法查找装载的class主类中
“public static void main(String[] args)”方法,并判断该方法是否为public方法,然后调用JNIEnv实例的CallStaticVoidMethod方法调用该java类的main方法。

总结
由上面的代码分析可以看出几个问题。
a、为什么JDK和JRE不一定通过安装,直接拷到硬盘上,设置path环境变量就可以执行。因为java运行获取jre路径的首选方法正是直接通过获取java.exe绝对路径来判断的,如果通过修改注册表选项而不设置path环境变量也可以找到jre路径所在。修改方法如下:
首先我们将java.exe拷到任意目录下,我的拷到e:emp下,在cmd中运行:
清空path环境变量
E:emp>set path=
E:emp>java
Error opening registry key 'SoftwareJavaSoftJava Runtime Environment'
Error: could not find java.dll
Error: could not find Java 2 Runtime Environment.

导入如下注册表文件(java.reg)

Windows Registry Editor Version 5.00[HKEY_LOCAL_MACHINESOFTWAREJavaSoft][HKEY_LOCAL_MACHINESOFTWAREJavaSoftJava Runtime Environment]"CurrentVersion"="1.4"[HKEY_LOCAL_MACHINESOFTWAREJavaSoftJava Runtime Environment1.4]"JavaHome"="D:javaj2sdk1.4.2_04jre"


再执行显示执行正常,如下:

E:emp>javaUsage: java [-options] class [args...]           (to execute a class)   or  java [-options] -jar jarfile [args...]           (to execute a jar file)where options include:    -client       to select the "client" VM    -server       to select the "server" VM    -hotspot      is a synonym for the "client" VM  [deprecated]                  The default VM is client.    -cp-classpathA ; separated list of directories, JAR archives,                  and ZIP archives to search for class files.    -D=set a system property    -verbose[:class|gc|jni]                  enable verbose output    -version      print product version and exit    -showversion  print product version and continue    -? -help      print this help message    -X            print help on non-standard options    -ea[:...|:]    -enableassertions[:...|:]                  enable assertions    -da[:...|:]    -disableassertions[:...|:]                  disable assertions    -esa | -enablesystemassertions                  enable system assertions    -dsa | -disablesystemassertions                  disable system assertions

b、java.exe是通过jvm.cfg文件或直接指定jvm.dll路径来装载执行java程序的。
见上面例子。
c、不同实现版本的jvm.dll必然存在一个名为:JNI_CreateJavaVM的导出函数,
java.exe正是通过调用该函数获得JNIEnv调用接口来装载执行class类的。这个
函数也是我们下一步研究java vm实作技巧的研究出发点。
JNI_CreateJavaVM函数位于:hotspotclass="lazy" data-srcsharevmprimsjni.cpp文件中。[@more@]

看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注编程网行业资讯频道,感谢您对编程网的支持。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

怎么用java源代码分析jvm.dll装载过程

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

怎么用java源代码分析jvm.dll装载过程

怎么用java源代码分析jvm.dll装载过程,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。简述众所周知java.exe是java class文件的执行程序,但
2023-06-03

JVM.dll装载过程与源代码的示例分析

今天就跟大家聊聊有关JVM.dll装载过程与源代码的示例分析,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。JVM.dll是一个包含可由多个程序同时使用的代码和数据的库。例如,在Win
2023-06-17

怎么用源代码分析FileZilla

本篇文章给大家分享的是有关怎么用源代码分析FileZilla,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。FileZilla是一种快速、可信赖的FTP客户端以及服务器端开放源代
2023-06-16

如何用Play源代码分析Server启动过程

这期内容当中小编将会给大家带来有关如何用Play源代码分析Server启动过程,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。Play是个Rails风格的Java Web框架。如何调试请看此处。以下进入正题
2023-06-17

如何用JVM源码分析Java对象的创建过程

这篇文章将为大家详细讲解有关如何用JVM源码分析Java对象的创建过程,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。基于HotSpot实现对Java对象的创建过程进行深入分析。定义两个简单的
2023-06-17

剖析Python源代码编制过程是怎么样的

剖析Python源代码编制过程是怎么样的,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。Python语言中提供的re模块能支持正则表达式,还提供SGML,XML分析模块,大多数的
2023-06-17

Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析

在前面几篇文章中,我们详细介绍了Android系统进程间通信机制Binder的原理,并且深入分析了系统提供的Binder运行库和驱动程序的源代码。细心的读者会发现,这几篇文章分析的Binder接口都是基于C/C++语言来实现
2022-06-06

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录