JVM源码剖析之System.getProperty实现

版本信息

jdk版本:jdk8u40
操作系统:Mac

System.getProperty 方法大家并不陌生,在各大框架源码中都能见到,项目中也能使用到,那么此篇文章将带你揭开System.getProperty方法底层实现。

System.getProperty 可以拿到当前系统属性,比如当前操作系统的属性、动态链接库位置、编码集、当前虚拟机的版本等等一系列系统属性。当然,你可以把它理解为整个系统上下文的一个存储数据的集合,你可以往里面set属性,任何地点get取出,并且线程安全。下面案例是展示了默认情况下所有的属性(所有的key都展示出来了,项目中如需使用,可以先遍历一次再寻找)

public static void main(String[] args) {Properties properties = System.getProperties();Iterator<Map.Entry<Object, Object>> iterator = properties.entrySet().iterator();while (iterator.hasNext()){Map.Entry<Object, Object> next = iterator.next();System.out.println("key:"+next.getKey()+";value:"+next.getValue());}
}

接下来直接看getProperty源码,实现非常非常非常非常的简单。在System类中维护了一个Properties类,直接从Properties中取出数据。而Properties实现了Hashtable,所以线程也是安全的。

public static String getProperty(String key) {…………return props.getProperty(key);
}

此时,我们更加关心Properties的数据来源,所以我们找到初始化Properties的地方。

private static void initializeSystemClass() {props = new Properties();initProperties(props);  …………}private static native Properties initProperties(Properties props);

而在Java层面找破头都找不到谁调用的initializeSystemClass方法,实际上这里是JVM初始化的过程中调用的此方法,所以肯定找不到,所以我们看到Hotspot中初始化的源码 src/share/vm/runtime/thread.cpp 文件中 create_vm 方法对于System类的初始化

jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {…………// 加载并初始化java_lang_System类。initialize_class(vmSymbols::java_lang_System(), CHECK_0);call_initializeSystemClass(CHECK_0);…………
}static void call_initializeSystemClass(TRAPS) {// 拿到加载好的类对象(在Hotspot中Klass代表类)Klass* k =  SystemDictionary::resolve_or_fail(vmSymbols::java_lang_System(), true, CHECK);instanceKlassHandle klass (THREAD, k);JavaValue result(T_VOID);// 调用java_lang_System类中静态方法initializeSystemClass// 这恰好,也是我们在Java层面寻找不到的调用JavaCalls::call_static(&result, klass, vmSymbols::initializeSystemClass_name(),vmSymbols::void_method_signature(), CHECK);
}

既然initializeSystemClass方法的调用方我们找到了,此时就需要看到initProperties这个native方法对于Properties的初始化工作。

/src/share/native/java/lang/System.c 文件中对于initProperties这个native方法的实现。

JNIEXPORT jobject JNICALL
Java_java_lang_System_initProperties(JNIEnv *env, jclass cla, jobject props)
{char buf[128];// 获取到系统属性java_props_t *sprops = GetJavaProperties(env);// 获取到Properties的put方法签名jmethodID putID = (*env)->GetMethodID(env,(*env)->GetObjectClass(env, props),"put","(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");// 获取到Properties的remove方法签名jmethodID removeID = (*env)->GetMethodID(env,(*env)->GetObjectClass(env, props),"remove","(Ljava/lang/Object;)Ljava/lang/Object;");// 获取到Properties的getProperty方法签名jmethodID getPropID = (*env)->GetMethodID(env,(*env)->GetObjectClass(env, props),"getProperty","(Ljava/lang/String;)Ljava/lang/String;");// 调用Properties的put方法往Properties里面添加属性PUTPROP(props, "java.specification.version",JDK_MAJOR_VERSION "." JDK_MINOR_VERSION);PUTPROP(props, "java.specification.name","Java Platform API Specification");PUTPROP(props, "os.name", sprops->os_name);PUTPROP(props, "os.version", sprops->os_version);PUTPROP(props, "os.arch", sprops->os_arch);…………// 把JVM启动时设置的参数添加// 可能是JVM自带的,也有可能是-D等等命令行设置的ret = JVM_InitProperties(env, props);…………return ret;
}
  1. 通过GetJavaProperties方法获取到系统属性
  2. initProperties这个native方法把Properties传入,然后通过PUTPROP宏往Properties里面添加各种系统属性
  3. 调用JVM_InitProperties方法,把JVM自带的,也有可能是-D等等命令行设置的系统属性添加到Properties中
JVM_ENTRY(jobject, JVM_InitProperties(JNIEnv *env, jobject properties))JVMWrapper("JVM_InitProperties");ResourceMark rm;Handle props(THREAD, JNIHandles::resolve_non_null(properties));// 把JVM的参数添加到Properties中for (SystemProperty* p = Arguments::system_properties(); p != NULL; p = p->next()) {PUTPROP(props, p->key(), p->value());}…………return properties;
JVM_ENDstatic SystemProperty*  system_properties()   { return _system_properties; }

这里调用Arguments::system_properties()方法得到SystemProperty对象,SystemProperty对象存放JVM所有的系统参数,所以这里是在遍历JVM中所有的系统参数。最后,我们可以看一下这些JVM参数何时添加的。src/share/vm/runtime/arguments.cpp 文件中init_system_properties方法

void Arguments::init_system_properties() {// 添加到SystemProperty集合中PropertyList_add(&_system_properties, new SystemProperty("java.vm.specification.name","Java Virtual Machine Specification",  false));PropertyList_add(&_system_properties, new SystemProperty("java.vm.version", VM_Version::vm_release(),  false));PropertyList_add(&_system_properties, new SystemProperty("java.vm.name", VM_Version::vm_name(),  false));PropertyList_add(&_system_properties, new SystemProperty("java.vm.info", VM_Version::vm_info_string(),  true));_java_ext_dirs = new SystemProperty("java.ext.dirs", NULL,  true);_java_endorsed_dirs = new SystemProperty("java.endorsed.dirs", NULL,  true);_sun_boot_library_path = new SystemProperty("sun.boot.library.path", NULL,  true);_java_library_path = new SystemProperty("java.library.path", NULL,  true);_java_home =  new SystemProperty("java.home", NULL,  true);_sun_boot_class_path = new SystemProperty("sun.boot.class.path", NULL,  true);_java_class_path = new SystemProperty("java.class.path", "",  true);// 添加到SystemProperty集合中PropertyList_add(&_system_properties, _java_ext_dirs);PropertyList_add(&_system_properties, _java_endorsed_dirs);PropertyList_add(&_system_properties, _sun_boot_library_path);PropertyList_add(&_system_properties, _java_library_path);PropertyList_add(&_system_properties, _java_home);PropertyList_add(&_system_properties, _java_class_path);PropertyList_add(&_system_properties, _sun_boot_class_path);os::init_system_properties_values();
}

还有在解析-D 等等java命令参数时也会添加,因为-D设置的属性是添加到System的Properties中

src/share/vm/runtime/arguments.cpp 文件中 parse_each_vm_init_arg方法

// 解析-D
else if (match_option(option, "-D", &tail)) {// 添加到SystemProperty集合中if (!add_property(tail)) {return JNI_ENOMEM;}…………
}bool Arguments::add_property(const char* prop) {const char* eq = strchr(prop, '=');char* key;const static char ns[1] = {0};char* value = (char *)ns;// 解析keysize_t key_len = (eq == NULL) ? strlen(prop) : (eq - prop);key = AllocateHeap(key_len + 1, mtInternal);strncpy(key, prop, key_len);key[key_len] = '\0';// 解析value// key和value用=号隔开if (eq != NULL) {size_t value_len = strlen(prop) - key_len - 1;value = AllocateHeap(value_len + 1, mtInternal);strncpy(value, &prop[key_len + 1], value_len + 1);}// 添加到SystemProperty集合中PropertyList_unique_add(&_system_properties, key, value);return true;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/29623.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Zookeeper特性与节点数据类型详解

CAP&Base理论 CAP理论 cap理论是指对于一个分布式计算系统来说&#xff0c;不可能满足以下三点: 一致性 &#xff1a; 在分布式环境中&#xff0c;一致性是指数据在多个副本之间是否能够保持一致的 特性&#xff0c;等同于所有节点访问同一份最新的数据副本。在一致性的需…

ChatGPT在大规模数据处理和信息管理中的应用如何?

ChatGPT作为一种强大的自然语言处理模型&#xff0c;在大规模数据处理和信息管理领域有着广泛的应用潜力。它可以利用其文本生成、文本理解和问答等能力&#xff0c;为数据分析、信息提取、知识管理等任务提供智能化的解决方案。以下将详细介绍ChatGPT在大规模数据处理和信息管…

Langchain module ‘hnswlib‘ has no attribute ‘Index‘ 错误解决

Langchain module hnswlib has no attribute Index 错误解决 使用 Langchain 操作 Chroma 向量数据库时&#xff0c;报一下错误信息&#xff0c; module hnswlib has no attribute Index试着重装了不同 hnswlib 版本没有解决&#xff0c;最后解决方法是&#xff0c;不要使用 h…

Apache DolphinScheduler 3.1.8 版本发布,修复 SeaTunnel 相关 Bug

近日&#xff0c;Apache DolphinScheduler 发布了 3.1.8 版本。此版本主要基于 3.1.7 版本进行了 bug 修复&#xff0c;共计修复 16 个 bug, 1 个 doc, 2 个 chore。 其中修复了以下几个较为重要的问题&#xff1a; 修复在构建 SeaTunnel 任务节点的参数时错误的判断条件修复 …

《24海南大学835软件工程考研经验贴》

1.经验之谈 首先&#xff0c;我是一个二战的考生&#xff0c;一战给我带来的经验有几点。第一&#xff0c;数学、专业课这两门越早复习越好&#xff0c;越拖到后面你就会发现来不及了&#xff0c;这学不完&#xff0c;那学不完的。第二、我认为是比较关键的一点&#xff0c;一定…

玩转graphQL

转载至酒仙桥的玩转graphQL - SecPulse.COM | 安全脉搏 前言 在测试中我发现了很多网站开始使用GraphQL技术&#xff0c;并且在测试中发现了其使用过程中存在的问题&#xff0c;那么&#xff0c;到底GraphQL是什么呢&#xff1f;了解了GraphQL后能帮助我们在渗透测试中发现哪些…

2 指针与数组:理解指针与数组的关系与转换

推荐最近在工作学习用的一款好用的智能助手AIRight 网址是www.airight.fun。 引言 在计算机科学中&#xff0c;指针与数组是两个基础且重要的概念。指针是一个用于存储变量地址的变量&#xff0c;而数组是一系列相同类型的元素的集合。虽然指针和数组看起来是两个不同的概念&…

在Mac本地搭建Kubernetes和Istio的详细教程

系列文章目录 文章目录 系列文章目录前言一、安装Docker和kind二、创建kind集群三、安装Istio四、部署示例应用五、配置Ingress Gateway六、访问示例应用总结前言 Kubernetes(简称K8s)是一个开源的容器编排平台,用于自动化部署、扩展和管理容器化应用程序。而Istio是一个服…

如何使用HAL库手动配置一个可输出可输入的引脚

在使用CubeMX配置GPIO口时的时候&#xff0c;对于某一个引脚只能选择用来输出或者输入。而有时我们需要在STM32上使用一些外设&#xff0c;比如DHT11温湿度传感器&#xff0c;其中的DATA口需要既能接收信号又能发送信号&#xff0c;所以我们可以参照CubeMX自动生成的GPIO初始化…

c++11 标准模板(STL)(std::basic_fstream)(三)

定义于头文件 <fstream> template< class CharT, class Traits std::char_traits<CharT> > class basic_fstream : public std::basic_iostream<CharT, Traits> 类模板 basic_fstream 实现基于文件的流上的高层输入/输出。它将 std::basic_i…

常见分布式ID解决方案总结:数据库、算法、开源组件

常见分布式ID解决方案总结 分布式ID分布式ID方案之数据库数据库主键自增数据库号段模式Redis自增MongoDB 分布式ID方案之算法UUIDSnowflake(雪花算法) 雪花算法的使用IdWorker工具类配置分布式ID生成器 分布式ID方案之开源组件uid- generator(百度)Tinyid&#xff08;滴滴&…

【LangChain学习】基于PDF文档构建问答知识库(三)实战整合 LangChain、OpenAI、FAISS等

接下来&#xff0c;我们开始在web框架上整合 LangChain、OpenAI、FAISS等。 一、PDF库 因为项目是基于PDF文档的&#xff0c;所以需要一些操作PDF的库&#xff0c;我们这边使用的是PyPDF2 from PyPDF2 import PdfReader# 获取pdf文件内容 def get_pdf_text(pdf):text "…

视频网站如何选择国外服务器?

​ 视频网站如何选择国外服务器? 地理位置&#xff1a;选择靠近目标用户群体的国外服务器位置是至关重要的。若用户主要集中在中国以外的地区&#xff0c;因您应选择位于用户所在地附近的服务商&#xff0c;以确保视频的传输速度。 带宽和速度&#xff1a;选择带宽足够且方便升…

如何解决 Elasticsearch 查询缓慢的问题以获得更好的用户体验

作者&#xff1a;Philipp Kahr Elasticsearch Service 用户的重要注意事项&#xff1a;目前&#xff0c;本文中描述的 Kibana 设置更改仅限于 Cloud 控制台&#xff0c;如果没有我们支持团队的手动干预&#xff0c;则无法进行配置。 我们的工程团队正在努力消除对这些设置的限制…

传统图像算法 - 运动目标检测之KNN运动背景分割算法

以下代码用OpenCV实现了视频中背景消除和提取的建模&#xff0c;涉及到KNN&#xff08;K近邻算法&#xff09;&#xff0c;整体效果比较好&#xff0c;可以用来进行运动状态分析。 原理如下&#xff1a; 背景建模&#xff1a;在背景分割的开始阶段&#xff0c;建立背景模型。 …

深入探索Linux文件链接技术:ln命令的妙用

当谈及 Linux 系统中的文件管理和链接技术&#xff0c;ln 命令是一个不可或缺的工具。ln 命令用于创建硬链接和软链接&#xff0c;它在 Linux 文件系统中发挥着重要作用&#xff0c;为用户提供了更大的灵活性和组织能力。在本文中&#xff0c;我们将深入探讨 ln 命令是什么&…

1999-2021年全国各地级市专利申请与获得情况、绿色专利申请与获得情况面板数据

1999-2021年全国各地级市专利申请与获得情况、绿色专利申请与获得情况面板数据 1、时间&#xff1a;2000-2021年 2、来源&#xff1a;国家知识产权局 3、范围&#xff1a;地级市&#xff08;具体每年地级市数量参看下文图片&#xff09; 4、指标&#xff1a;申请专利数&…

【C/C++】C语言位图操作实例(亲测)

C语言中的位图操作通常用于处理大量的二进制数据&#xff0c;例如图像处理、压缩算法等。以下是一些C语言中的位图操作实例&#xff1a; 设置位图中的某一位 void set_bit(unsigned char *bitmap, int bit) {bitmap[bit / 8] | (1 << (bit % 8)); }这个函数将位图中的第…

【leetcode】1. 两数之和(easy)

给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素在答案里不能重复出现。 你可以按任意顺序返回…

Jenkins 中 shell 脚本执行失败却不自行退出

Jenkins 中 执行 shell 脚本时&#xff0c;有时候 shell 执行失败了&#xff0c;或者判断结果是错误的&#xff0c;但是 Jenkins 执行完成后确提示成功 success 。 此时&#xff0c;可以通过条件判断来解决这个问题&#xff0c;让 Jenkins 强制退出并提示执行失败 failed 。 …