1.jvmԴ?码地??ַ
2.JVM详解之:HotSpot VM中的Intrinsic methods
3.Jvm-Sandbox原理分析-Sandbox的启动-01
4.OpenJDK17-JVM 源码阅读 - ZGC - 并发标记 | 京东物流技术团队
jvmԴ???ַ
Java虚拟机(JVM)是Java语言的基础,负责执行Java字节码。码地它实现跨平台性,码地使Java程序能在不同硬件和操作系统上运行,码地无需修改代码。码地编写的码地公开课网站源码Java源代码生成字节码,JVM加载并执行。码地提供内存管理、码地垃圾回收、码地安全性、码地线程管理等功能,码地确保程序稳定、码地安全、码地兼容。码地JVM适用于Windows、码地Linux、macOS等系统,实现代码一次编写,到处运行。
核心功能包括:解释或编译字节码为本地机器代码,实现程序执行;提供丰富的网狐源码编译内存管理、安全性和多线程支持,保障程序可靠性和安全性;确保跨平台兼容性,无需针对特定平台修改代码。字节码与不同系统的JVM结合,构成Java语言“一次编译,随处运行”的独特优势。
综上所述,JVM作为Java程序运行的核心,其功能强大,确保了Java语言的跨平台性、稳定性和安全性。它将字节码转换为本地代码,执行程序。通过内存管理、垃圾回收、安全机制和线程管理,确保程序在各种环境下运行顺畅。字节码与不同操作系统上的JVM协同工作,实现了Java程序的“一次编写,到处运行”。私彩 源码java
Java虚拟机(JVM)作为Java程序执行的关键,实现跨平台性,确保程序在不同系统上稳定运行。它执行字节码,提供内存管理、垃圾回收、安全和线程支持,保障Java程序的可靠性和兼容性。通过将字节码转换为本地代码,JVM使Java程序能够在Windows、Linux、macOS等操作系统上运行,实现“一次编译,到处运行”的优势。
JVM详解之:HotSpot VM中的Intrinsic methods
内置方法是编译器内置的方法实现,它们在给定编程语言中使用,由编译器专门处理。内置方法通常在程序请求优化时才启用,以提高效率。因为内置方法是在线生成字体源码在编译器内部实现的,所以不同的虚拟机,其内置方法是不一样的。内置方法可以在Java源代码级别看起来与非内置方法一样,但它们的区别在于JVM的实现。有些方法在普通Java代码中无法实现,如sun.misc.Unsafe.compareAndSwapInt(),只能通过JNI或内置方法来实现,实现对Java语义的扩展。在Hotspot VM中,内置方法通常在src/share/vm/classfile/vmSymbols.hpp类中。通过参数查看代码中调用的方法是否为内置方法,或者通过底层汇编语言查看。内置方法大部分都是内联方法,通过减少函数调用开销的技术实现。内置方法的实现由三种编译器完成:javac将Java源代码编译成为字节码,在这一层只有数学方法和bootstrapping的MethodHandle实现;JIT的Client Compiler (C1);JIT的Server Compiler (C2)。例如,java.lang.System.currentTimeMillis()方法在Interpreter级别没有intrinsified,因为它是一个native方法,通过JNI调用底层的php搜索代码源码C++实现。而在C1和C2级别使用intrinsified,直接调用os::javaTimeMillis(),减少JNI的使用,提升效率。内置方法的实现可以通过修改底层的JVM实现完成。Graal是一个用Java编写的JIT编译器,可以使用Java来实现Intrinsic方法,对于不熟悉C++的开发者来说非常友好。通过Graal,内置方法的实现变得简单且容易操作。内置方法是JVM中非常有用的特性,能够显著提高程序效率,是编程时值得考虑的技术之一。
Jvm-Sandbox原理分析-Sandbox的启动-
Jvm-Sandbox的启动(一):sandbox.sh脚本分析
Sandbox的启动是通过其内置的shell脚本 sandbox.sh 开始执行的,一切的开始皆可从该脚本中探寻出结果。脚本有一定的代码量,大概有+行,这里将该脚本分为如下几个部分进行讲解:
1、变量定义过程这个过程首先预定义了接下来即将使用的一些变量。代码如下:
# 定义sandbox的home目录,并为其赋值 typeset SANDBOX_HOME_DIR [[ -z ${ SANDBOX_HOME_DIR} ]] && SANDBOX_HOME_DIR=${ PWD}/..# 定义 SANDBOX_USER,并为其赋值 typeset SANDBOX_USER=${ USER} [[ -z ${ SANDBOX_USER} ]] && SANDBOX_USER=$(whoami)# 定义 SANDBOX_SERVER_NETWORK typeset SANDBOX_SERVER_NETWORK# 定义lib目录,这个目录下主要存放jar包 typeset SANDBOX_LIB_DIR=${ SANDBOX_HOME_DIR}/lib# 定义 SANDBOX_TOKEN_FILE typeset SANDBOX_TOKEN_FILE="${ HOME}/.sandbox.token"# 定义JVM参数 SANDBOX_JVM_OPS typeset SANDBOX_JVM_OPS="-XmsM -XmxM -Xnoclassgc -ea"# 定义目标JVM的进程号,后面的agent主要attach到该JVM进程上 typeset TARGET_JVM_PID# 定义目标机器IP以及默认机器IP typeset TARGET_SERVER_IP typeset DEFAULT_TARGET_SERVER_IP="0.0.0.0"# 定义目标进程端口 typeset TARGET_SERVER_PORT# 定义名称空间 typeset TARGET_NAMESPACE typeset DEFAULT_NAMESPACE="default"注释和变量命名已经描绘的非常清楚了,在看后面代码遇到忘记了的变量可以到这里来回顾下。
这里为其中一些变量补充说明:
SANDBOX_HOME_DIR:shell脚本中,-z表示检测紧跟的字符串长度是否为0,如果为0返回true。这里使用短路与,如果 ${ SANDBOX_HOME_DIR} 为0,则使用 ${ PWD}/.. 的目录作为sandbox的home目录。这种方式表示优先使用环境变量 SANDBOX_HOME_DIR,如果未定义环境变量SANDBOX_HOME_DIR,则使用当前目录。
SANDBOX_TOKEN_FILE:这个文件主要存放了sandbox attach记录,包括attach进程的host:port。
TARGET_SERVER_IP:一般情况下,我们都是将整个工程打包后上传至目标机器,然后在目标机器上执行该shell脚本,因此默认机器IP一般为localhost即可。
2、执行入口执行入口就比较简单了,就一行代码,其中${ @}会保存我们传递给该shell脚本的所有参数:
main "${ @}"比方说,我们以如下命令启动脚本,则${ @} 就包含了-p 这个参数
./sandbox.sh -p 、main函数main函数是该脚本的重要方法,也是脚本的执行入口,它主要完成了以下几件事:
其代码如下所示:
function main() { # 遍历脚本参数 while getopts "hp:vFfRu:a:A:d:m:I:P:ClSn:X" ARG; do case ${ ARG} in h) # 帮助手册函数,大家可以自行翻阅源码查看 usage exit ;; # 赋值PID p) TARGET_JVM_PID=${ OPTARG} ;; v) OP_VERSION=1 ;; l) OP_MODULE_LIST=1 ;; R) OP_MODULE_RESET=1 ;; F) OP_MODULE_FORCE_FLUSH=1 ;; f) OP_MODULE_FLUSH=1 ;; u) OP_MODULE_UNLOAD=1 ARG_MODULE_UNLOAD=${ OPTARG} ;; a) OP_MODULE_ACTIVE=1 ARG_MODULE_ACTIVE=${ OPTARG} ;; A) OP_MODULE_FROZEN=1 ARG_MODULE_FROZEN=${ OPTARG} ;; d) OP_DEBUG=1 ARG_DEBUG=${ OPTARG} ;; m) OP_MODULE_DETAIL=1 ARG_MODULE_DETAIL=${ OPTARG} ;; # 赋值IP I) TARGET_SERVER_IP=${ OPTARG} ;; # 赋值PORT P) TARGET_SERVER_PORT=${ OPTARG} ;; C) OP_CONNECT_ONLY=1 ;; S) OP_SHUTDOWN=1 ;; n) OP_NAMESPACE=1 ARG_NAMESPACE=${ OPTARG} ;; X) set -x ;; ?) usage exit_on_err 1 ;; esac done # 重置环境 reset_for_env # 校验权限 check_permission# 根据不同的参数,进行相应处理 # 如果没有指定IP,则使用默认值 [ -z "${ TARGET_SERVER_IP}" ] && TARGET_SERVER_IP="${ DEFAULT_TARGET_SERVER_IP}"# 如果没有指定port,使用默认值 [ -z "${ TARGET_SERVER_PORT}" ] && TARGET_SERVER_PORT=0# reset NAMESPACE [[ ${ OP_NAMESPACE} ]] && TARGET_NAMESPACE=${ ARG_NAMESPACE} [[ -z ${ TARGET_NAMESPACE} ]] && TARGET_NAMESPACE=${ DEFAULT_NAMESPACE}if [[ ${ OP_CONNECT_ONLY} ]]; then [[ 0 -eq ${ TARGET_SERVER_PORT} ]] && exit_on_err 1 "server appoint PORT (-P) was missing" SANDBOX_SERVER_NETWORK="${ TARGET_SERVER_IP};${ TARGET_SERVER_PORT}" else # -p was missing [[ -z ${ TARGET_JVM_PID} ]] && exit_on_err 1 "PID (-p) was missing." # attach jvm的核心方法 attach_jvm fi# -v show version [[ -n ${ OP_VERSION} ]] && sandbox_curl_with_exit "sandbox-info/version"# -l list loaded modules [[ -n ${ OP_MODULE_LIST} ]] && sandbox_curl_with_exit "sandbox-module-mgr/list"# -F force flush module [[ -n ${ OP_MODULE_FORCE_FLUSH} ]] && sandbox_curl_with_exit "sandbox-module-mgr/flush" "&force=true"# -f flush module [[ -n ${ OP_MODULE_FLUSH} ]] && sandbox_curl_with_exit "sandbox-module-mgr/flush" "&force=false"# -R reset sandbox [[ -n ${ OP_MODULE_RESET} ]] && sandbox_curl_with_exit "sandbox-module-mgr/reset"# -u unload module [[ -n ${ OP_MODULE_UNLOAD} ]] && sandbox_curl_with_exit "sandbox-module-mgr/unload" "&action=unload&ids=${ ARG_MODULE_UNLOAD}"# -a active module [[ -n ${ OP_MODULE_ACTIVE} ]] && sandbox_curl_with_exit "sandbox-module-mgr/active" "&ids=${ ARG_MODULE_ACTIVE}"# -A frozen module [[ -n ${ OP_MODULE_FROZEN} ]] && sandbox_curl_with_exit "sandbox-module-mgr/frozen" "&ids=${ ARG_MODULE_FROZEN}"# -m module detail [[ -n ${ OP_MODULE_DETAIL} ]] && sandbox_curl_with_exit "sandbox-module-mgr/detail" "&id=${ ARG_MODULE_DETAIL}"# -S shutdown [[ -n ${ OP_SHUTDOWN} ]] && sandbox_curl_with_exit "sandbox-control/shutdown"# -d debug if [[ -n ${ OP_DEBUG} ]]; then sandbox_debug_curl "module//post/OpenJDK-JVM 源码阅读 - ZGC - 并发标记 | 京东物流技术团队
ZGC简介:
ZGC是Java垃圾回收器的前沿技术,支持低延迟、大容量堆、染色指针、读屏障等特性,自JDK起作为试验特性,JDK起支持Windows,JDK正式投入生产使用。在JDK中已实现分代收集,预计不久将发布,性能将更优秀。
ZGC特征:
1. 低延迟
2. 大容量堆
3. 染色指针
4. 读屏障
并发标记过程:
ZGC并发标记主要分为三个阶段:初始标记、并发标记/重映射、重分配。本篇主要分析并发标记/重映射部分源代码。
入口与并发标记:
整个ZGC源码入口是ZDriver::gc函数,其中concurrent()是一个宏定义。并发标记函数是concurrent_mark。
并发标记流程:
从ZHeap::heap()进入mark函数,使用任务框架执行任务逻辑在ZMarkTask里,具体执行函数是work。工作逻辑循环从标记条带中取出数据,直到取完或时间到。此循环即为ZGC三色标记主循环。之后进入drain函数,从栈中取出指针进行标记,直到栈排空。标记过程包括从栈取数据,标记和递归标记。
标记与迭代:
标记过程涉及对象迭代遍历。标记流程中,ZGC通过map存储对象地址的finalizable和inc_live信息。map大小约为堆中对象对齐大小的二分之一。接着通过oop_iterate函数对对象中的指针进行迭代,使用ZMarkBarrierOopClosure作为读屏障,实现了指针自愈和防止漏标。
读屏障细节:
ZMarkBarrierOopClosure函数在标记非静态成员变量的指针时触发读屏障。慢路径处理和指针自愈是核心逻辑,慢路径标记指针,快速路径通过cas操作修复坏指针,并重新标记。
重映射过程:
读屏障触发标记后,对象被推入栈中,下次标记循环时取出。ZGC并发标记流程至此结束。
问题回顾:
本文解答了ZGC如何标记指针、三色标记过程、如何防止漏标、指针自愈和并发重映射过程的问题。
扩展思考:
ZGC在指针上标记,当回收某个region时,如何得知对象是否存活?答案需要结合标记阶段和重分配阶段的代码。
结束语:
本文深入分析了ZGC并发标记的源码细节,对您有启发或帮助的话,请多多点赞支持。作者:京东物流 刘家存,来源:京东云开发者社区 自猿其说 Tech。转载请注明来源。