⑴ 技能篇:linux服务性能问题排查及jvm调优思路
vmstat 和 pidstat。vmvmstat 可查看系统总体的指标,pidstat则详细到每一个进程服务的指标
Swap 其实就是把一块磁盘空间或者一个本地文件,当成内存来使用。swap 换出拿孙,把进程暂时不用的内存数据存储到磁盘中,并释放这些数据占用的内存。swap 换入,在进程再次访问这族敏空些内存的时候,把它们从磁盘读到内存中来
当一个网络帧到达网卡后,网卡兆瞎会通过 DMA 方式,把这个网络包放到收包队列中;然后通过硬中断,告诉中断处理程序已经收到了网络包。接着,网卡中断处理程序会为网络帧分配内核数据结构(sk_buff),并将其拷贝到 sk_buff 缓冲区中;然后再通过软中断,通知内核收到了新的网络帧。内核协议栈从缓冲区中取出网络帧,并通过网络协议栈,从下到上逐层处理这个网络帧
⑵ JROCKIT 5.0——轻松玩转JVM
BEA JRockit Java虚拟派指脊机(JVM)所带来的不仅仅是性能的提升 本文探讨了JRockit R 版本可用的一些管理和使用方面的特性 概述了JRockit Mission Control分析工具套件 JRockit Management Console的试验性headless模式以及使用Ctrl Break Handler JRCMD 堆视图和code coverage与JVM进行交互
简介JRockit JVM不只是快 它还和JRockit Mission Control一起 组成一套执行运行时分析和内存泄漏检测的分析工具 JRockit Management Console包含在JRockit JDK中 本文将探讨JRockit Management Console的一种试验性的headless模式 它可以用于与来自命令行的基于JRockitJMX的管理代理进行交互 Ctrl Break Handler提供了一种向JRockit发送各种高级命令的方法 甚至是在它启动后 这些命令甚至可以远程调用 我在后文中会提及 最后 我探讨了试验性的code coverage JRockit开箱即用地提供了该特性
关于BEA JRockit的更多信息 参见dev dev网站的JRockit Proct Center
首先我将快速概述一下JRockit JVM可用的已确定的管理工具 然后我会转向缺少文档的试验性管理特性
JRockit Mission ControlJRockit R 版本引入了JRockit Mission Control工具套件 它包含的工具可以进行监控 管理 分析和消除Java应用程序内存泄漏 而不会引起通常与此类工具相关联的性能开销 Mission Control的低性能开销是因为使用了作为JRockit常规适应性动态调优的一部分而收集的数据 这还可以消除工具使用字节码装置修改系统执行特性时发生Heisenberg异常的问题 JRockit Mission Control功能可以根据需要随时可用 低性能开销也只在运行工具时有效 这些特征使得JRockit Mission Control成为专门用于生产中系统的工具
JRockit Mission Control中包含以下工具
JRockit Management ConsoleJRockit Management Console用于监逗衡控和管理多个JRockit实例 它捕获并显示关于垃圾收集器(GC)暂停 内存和CPU使用的实时数据 以及部署在JVM内部MBean服务器上的所有JMX MBean的信息 JVM管理包括尘渗对CPU相似性 垃圾收集策略和内存池大小的动态控制 JRockit Runtime AnalyzerJRockit Runtime Analyzer(JRA)是一个随需应变的 动态记录器 它生成关于JVM和正在运行的应用程序的详细记录 然后可以使用JRA应用程序对记录下来的配置文件进行离线分析 所记录的数据包括对方法和锁定的分析 还有垃圾收集统计信息 优化决策以及对象统计信息 JRockit Memory Leak DetectorJRockit Memory Leak Detector工具用来发现和查找内存泄漏原因 Memory Leak Detector的趋势分析器可以发现非常缓慢的泄漏 显示详细的堆统计信息(包括指向泄漏对象和分配位置的引用类型和实例) 并快速找出泄漏原因 Memory Leak Detector使用先进的图形化表现技术 以便更容易定位和理解有时比较复杂的信息关于JRockit Mission Control的更多信息 可以阅读文章An Introction to JRockit Mission Control 或者访问dev dev网站的JRockit Mission Control
JRockit Management Console的Headless模式(试验性)
JRockit Management Console是监控JRockit运行的工具 它包括两部分 一个运行在JVM进程中的JMX代理 一个使用图形化用户界面的独立客户端(关于它以及其它方面的更详细的信息 请参见An Introction to JRockit Mission Control) 其中 用户界面可以绘出部署在所连接的Java虚拟机中的任何MBean的数值属性的图形 图形密集的应用程序对资源的消耗可能会相当厉害 JRockit Management Console也不例外 可以引入text only(纯文本)模式 以便使用Management Console的通知功能和数据收集工具而不会导致整个GUI的开销
headless控制台引入了大量新的命令行参数 这同样适用于控制台的GUI版本 参数包括
参数 描述 headless 以headless模式启动控制台(不会加载与GUI相关的类) settings <settings file> 使用指定配置文舳H绻讷UI模式启动 并且该文件不存在 那么它将在关闭Management Console时创建 connectall 连接配置文件中所有可用连接(即原先使用GUI添加的) connect <connection > <connection > < > 使用GUI连接配置文件中可用的指定连接 autoconnect 自动连接到运行在启用JRockit发现协议(JRockit Discovery Protocol JDP)的管理服务器上的任何JRockit uptime <time in seconds> 将控制台运行一段指定的时间 然后自动关闭它 useraction <name> <delay in seconds> <period (optional)> 经过指定的时延后运行指定的用户动作 如果不指定period 动作将只执行一次 如果指定 动作将每过<period>秒就执行一次 version 打印Management Console的版本信息 并退出 locale <language> <country (optional)> 使用特定的地区启动控制台 比如 locale ja JP将以日语启动控制台(JRockit R 可用)
这里给出一个以headless模式启动Management Console的例子 读取指定配置文件 尝试连接所有已指定的JRockit 使用JRockit发现协议(JDP 下文讨论)积极查找新的JRockit 秒后将以每分钟一次的间隔向所有连接的JRockit发送Ctrl Break命令 一小时之后自动关闭 以前加入指定连接的所有通知规则(不管是通过使用GUI还是通过直接编辑配置文件添加的)将生效
java jar ManagementConsole jar headless settings C:Headlessconsolesettings xml connectall autoconnect uptime useraction ctrlbreak
用户动作是可以与JRockit Management Console上的一组连接进行交互的插件类 同样使用控制台配置文件来存储配置数据 用户动作显示在JRockit控制台图形用户界面的Plugins菜单下 headless模式中也可用 随控制台提供了两个默认用户动作 jrarecording用户动作 对连接的JRockit启动JRA记录 ctrlbreak用户动作 向连接的JRockit发送Ctrl Break命令(参见本文中关于Ctrl Break Handler和JRockit运行时分析器的小节) 要指定特定用户动作的参数 可以使用GUI进行配置 也可以编辑Management Console配置文件 后者可以在<user home>/ManagementConsole/ManagementConsole/consolesettings <version> xml文件中找到
编写自己的用户动作很容易 首先创建一个AbstractUserAction的子类 该示例演示了如何创建一个从所有连接的JRockit获取线程堆栈转储的用户动作
package example useractions; import java io IOException; import java util List; import nsole rjmx CommonRJMXNames; import nsole rjmx RJMXConnectorModel; import nsole useractions AbstractUserAction; /** * This is a simple user action getting stackmps from * the selected JRockits and printing them on stdout * * @author Marcus Hirt */ public class MyUserAction extends AbstractUserAction { public void executeAction(List connections) { for (RJMXConnectorModel connection : connections) { if (connection isConnected()) { try { System out println(CommonRJMXNames getThreadMXBean(connection) getThreadStackDump()); } catch (IOException e) { e printStackTrace(); } } } } }
接下来 需要在consolesettings xml文件中配置部属描述符 以便用户动作对于控制台可用 可以在配置文件中发现user_actions元素 它已经填充了一些user_action元素 示例动作的部署描述符应当以相同的样式输入 描述符看起来会是这样
<user_action> <user_action_class> example useractions MyUserAction</user_action_class> <user_action_name>stackmp</user_action_name> <user_action_menu_name>Stack Dump on stdout</user_action_menu_name> <user_action_description>Gets a stack mp from the selected JRockit(s) and mps it on stdout </user_action_description> </user_action>
这也使得用户动作在Plugins菜单下的用户界面中可见
当控制台启动或退出时 如果有设置/状态需要从配置文件加载/保存 只需重写exportToXml()/importFromXml()方法 如示例中所示
/** * @see nsole util XmlEnabled * #exportToXml( w c dom Element) */ public void exportToXml(Element parentNode) { super exportToXml(parentNode); XmlToolkit setSetting(parentNode MY_PROPERTY m_myVal); } /** * @see nsole util XmlEnabled * #initializeFromXml( w c dom Element) */ public void initializeFromXml(Element parentNode) { super initializeFromXml(parentNode); m_myVal = XmlToolkit getSetting(parentNode MY_PROPERTY DEFAULT_MY_VALUE)); }
注意 用户动作的名称是使用launcher启动参数时将引用的用户动作名称 菜单名是会在GUI菜单中显示的名称 更多的信息请参见user action docs和JLMEXT docs 注意 这只是一个试验性的功能 提供的文档还相当简单 编写定制的通知动作和约束的方式与此类似 更多信息请参见Management Console User Guide
JRockit发现协议(JDP)JDP(JRockit发现协议)是个简单且有效的协议 用于允许JRockit管理服务器向Management Console组播它的存在 下面的两个表分别列出了在服务器端和客户端控制JDP行为的系统属性
管理服务器的JDP属性 系统属性 描述 默认值 jrockit managementserver autodiscovery 启用JRockit发现协议 False jrockit managementserver discovery period 在两个ping之间需要等待多久(以毫秒为单位) jrockit managementl 活跃的跃点数 jrockit managementserver discovery address 所使用的组播地址 jrockit managementserver discovery port 所使用的组播端口
Management Console的JDP属性 系统属性 描述 默认值 nsole preferences jdp port 用于JRockit发现协议的端口 nsole preferences jdp address 所使用的组播地址
这里给出了在服务器端启用JDP的情况下 启动JRockit需要最少参数的示例
java Xmanagement Djrockit managementserver autodiscovery=true<your program>
Ctrl Break Handler
您是否曾经希望在JVM启动后可以使用一种轻松的方式与其交互?假如说您忘记添加 Xmanagement选项来启动管理服务器 或者您想改变运行系统中GC的冗余级别 这些现在很容易通过重新配置Ctrl Break Handler来完成 而且它不只是打印堆栈跟踪
用法
创建一个名为ctrlhandler act的文件 向ctrlhandler act文件添加命令(参见下文命令列表) 以 stop 结束文件 这是结束文件分析的保留命令 按下ctrl break 每一个命令都将以出现的顺序执行JRockit首先会在当前工作目录查找该文件 如果未找到 JRockit将在JVM目录中查找 如果仍然没有的话 JRockit将回退以生成一个常规的线程堆栈转储 JRockit将在每次按下ctrl break时读取act文件 因此用户可以在方便时重新配置该文件 而同时JRockit仍在运行
这里给出一个示例act文件 它首先打印时间戳 然后是用于启动JRockit的命令行 最后是一个线程堆栈转储 它还包括可以用于act文件的有用命令的列表
# Example ctrlhandler act file timestamp mand_line print_threads stop # set_filename filename=<file> [append=true] # Sets the file that all handlers following this mand will # use for printing You can have several set_filename mands # in a file It takes o arguments: filename and an optional # append to specify if you want to append to the file # or overwrite it Default is to overwrite the file # timestamp # Prints a timestamp # print_threads # The normal thread mp # verbosity [args=<ponents>] [filename=<file>] # Changes the verbosity level normally specified with Xverbose # version # Prints JRockit version information # mand_line # Prints the mand line used to start JRockit # print_object_summary # Prints heap usage statistics (how much heap is used per class) # together with a delta on how much this has changed since # the last invocation of this ctrl break handler # print_memusage # Prints a memory usage report of how JRockit is using # the memory # heap_diagnostics # Prints a detailed report of the heap including ascii graphics # over the heap layout # print_class_summary # Prints all loaded classes # print_utf pool # Print all UTF strings # jrarecording [filename=<file>] [time=<time>] [nativesamples=true] # Starts a JRA recording # run_optfile [filename=<file>] # See OptFile # start_management_server # Starts the new JMX based management agent # kill_management_server # Stops the management agent # start_rmp_server # Starts the old management server (actually the listening # socket that in turn starts servers whenever a connection # is established) # kill_rmp_server # Stops the old management server (actually shuts down the # listening socket) The only reason it isn t named # kill_rmp_server is that stop is a reserved keyword # that stops the parsing of the act file ;) # help [ctrl break handler] # Prints all available ctrl break handlers if no argument # is specified or help for the specified ctrl break handler # memleakserver [port=<port>] # Toggles the memleakserver If it hasn t been started # it will be started If it has already started it will be # shut down The default port is # verbose_referents action=[heap|full|nursery|start|stop] # Print verbose reference information # Parameters: # action=[heap|full|nursery|start|stop] # heap trigger a heap collection and output reference # information # full trigger a full heap collection (clears softly # reached soft referents) # nursery trigger a nursery collection (heap collection # if running without nursery) # start start writing reference information to default # verbose stream # stop stop writing reference information # print_exceptions # exceptions=[true|all|false] stacktraces=[true|all|false] # Enable printing of Java exceptions thrown in the VM # Parameters: # exceptions print exceptions # stacktraces print exceptions with stacktraces # At least one of the parameters is required # Values for the parameters can be true|all|false # true print all exceptions # except java/util/EmptyStackException # java/lang/ClassNotFoundException and # java/security/PrivilegedActionException # all print all exceptions # false don t print exceptions # To turn exception printing off pletely you need to set # exceptions = false even if it was turned # on by stacktraces = true JRCMD 使用JRCMD实用工具是一种新的调用Ctrl Break Handler的便捷方式 可在JRockit发行版的bin目录中找到它 用法 jrcmd <PID> <mand> <parameters>
JRCMD使用JRCMD实用工具是一种新的调用Ctrl Break Handler的便捷方式 可在JRockit发行版的bin目录中找到它
用法 jrcmd <PID> <mand> <parameters>
PID = 要在其中执行Ctrl Break Handler的JRockit进程的进程ID mand = 要执行的Ctrl Break Handler命令 parameters = Ctrl Break Handler的参数如果不指定选项(或者只指定 P) 那么将显示运行在本地机器上的所有JRockit的进程ID 如果PID设为 那么命令将发送给在本地机器上运行的所有JRockit JVM
要列出特定的JRockit中有哪些Ctrl Break Handler可用 可以使用help命令
jrcmd <PID> help
要想获得某个具体的Ctrl Break Handler的帮助信息 需要在help后添加Ctrl Break Handler的名称 比如
jrcmd help kill_management_server
也可以使用JRCMD列出指定进程的性能计数
jrcmd <PID> l
远程调用Ctrl Break Handler可以使用JRockit Management Console来远程调用Ctrl Break Handler 存在一个对JRockitConsoleMBean的操作 称为runCtrlBreakHandlerWithResult JRockit Management Console可以从属性浏览器调用对MBean的操作 这里有关于如何调用Ctrl Break Handler的逐步描述
连接到一个运行中的JRockit 右击该连接 选择Browse Attributes 展开 jrockit domain文件夹 选择JRockitConsole MBean 单击operations选项卡 查看可用操作 单击String parameter参数按钮 找到runCtrlBreakHandlerWithResult操作 输入希望执行的Ctrl Break Handler名称 语法与ctrlhandler act文件相同 按下OK 按下Execute按钮 执行操作试着输入 help 作为参数 将会列出所有可用的Ctrl Break Handler 如图 所示
图 从JRockit Management Console调用Ctrl Break Handler(单击图片查看大图)
堆视图(试验性)当分析应用程序如何使用某种垃圾收集策略时 在每一次GC后对堆进行快照将会非常有帮助 这有助于开发人员研究数据 比如碎片/压缩以及算法通常如何执行 但是快照中包含如此多的数据量以至于查看它没有什么意义 因此JRockit团队开发了一个提供图形化表示的小工具 以便更好地进行说明
图 显示了一个快照的例子(使用的是一个非常早的JRockit 预发布版本)
每一排表示一次垃圾收集 左边是开始的堆 右边是结束的堆 堆显示的右边是一个可配置图形 实心白 *** 域表示空白堆 黑 *** 域是充实区(也就是填充了对象的区域) 浅灰 *** 域是碎片区 红色 黄色和绿 *** 域是可配置图形 可以从命令行指定在可配置图形中显示什么 该工具依然很粗糙 对于用户也不够友好 不过毋庸置疑它对JRockit的终端用户非常有用 所以这是一个非常不错但是不能通用的工具
code coverage(试验性)很多开发人员在以某种方式使用他们的应用程序时 使用code coverage分析来研究诸如代码库中的多少以及哪些部分正在运行之类的状况 测试人员喜欢使用code coverage来度量测试套件覆盖应用程序的比例 但是 对于大型应用程序 由code coverage工具所引起的性能开销通常是被禁止的
JRockit内置了高性能的行code coverage 当启用code coverage运行时 代码将由记录行命中的捕获器生成 一旦某行被命中并记录 就删除捕获器 JRockit可以继续以接近全速的速度运行
要使JRockit记录code coverage数据 必须指定一个命令行选项
用法 Xcodecoverage
可以使用以下系统属性来控制该行为
系统属性 描述 decoverage filter=<filterspec> filterspec是个以分号(Windows)或冒号(Linux)隔开的筛选器字符串行表 它定义哪些类应当被覆盖 以 开头的筛选器字符串会被视为不应当覆盖的类
示例 decoverage filter=java/util/Hashtable;/bea/*; /bea/bla *
decoverage filterfile=<filename> 设置包含筛选器定义的文件的文件名 文件格式为每行一个筛选器字符串 decoverage outputfile=<filename> 设置存放输出的文件 如果写入<filename>_ 输出文件不能被打开 那么将尝试<filename>_ 以此类推 在多个JVM共享一个公共命令行的情况中 这可能会很有用 decoverage testid=<id string> 设置初始测试标识符 decoverage verbose 使code coverage更为详细 适用于在覆盖文件(均是纯文本文件)中执行文本比较 decoverage appendoutput 设置对输出文件的写入为追加而不是覆盖
这里给出特定于code coverage的参数 用于生成如下图中所示的数据
Xcodecoverage decoverage filter=/jrockit/console/*;/jrockit/mon/* decoverage outputfile=console_coverage txt
在内部 由一个code coverage小工具来解释JRockit所生成的数据 如图 所示
图 code coverage工具的输出示例
lishixin/Article/program/Java/hx/201311/26298
⑶ jvm如何定位一个对象
1、使用句柄:
如果使用句柄访问的话,那么java堆将会划分出历晌一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据和类型数据各自的地址信息
优点:使用句柄的最大的好处就是reference中存储的时稳定的句柄地址,即的对象移动(例如GC垃圾回肢顷锋收时)时只会改变句柄中的书库数据的指针,reference本身不需要修改。
2、使用直接指针:
reference中存储的直接就是对象的地址
优点:直接指针访问方式最大的好处就是速度快,乎销他节省了一次指针定位的时间开销,但是由于对象会经常被访问,因此这项开销积少成多后也是一项非常可观的执行成本
⑷ JVM系列之类的准备与解析
一、前言
每个类的生命周期,和生命一样,都有起点与终点;
每个类都会在自己的生命周期里,完成自己的使命--使命必达!
类在这个阶段,被赋予了它的天赋与使命;
二、准备阶段
为class对象和类元数据信息分配内存空间,并初始化静态变量和常量值,这里变量使用的内存都在方法区中分配;
这里是初始化仅包括类变量(被static修饰的变量),而不包括实例变量,实例变量将会在对象实例化随着对象一起分配在Java堆中;
这里所说的初始值“通常情况”下是数据类型的零值,例如:
public static int value=110;
这里value赋的初始值洞饥是0不是110,这时候尚未开始任何Java方法,而把value赋值为110的 putstatic 指令是程序被编译后,存放于类构造器初始化方法之中,所以把value赋值为110的动作将在初始化阶段才会执行;
如果变量是被final关键字修饰,那么准备阶段就会被赋值为110,不必等到初始化阶段再赋值。
三、解析
该阶段是将jvm虚拟机中常量池的符号引用替换成直接引用,解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符。
1、类或接口的解析
第一步: 如果C不是一个数组类型,那么虚拟机会把代表N的权限定名传递给D的类加载器去加载这个类C。在加载的过程当中,由于元数据、字节码验证的操作,又可能触发其它类的加载动作,一旦出险任何异常,则解析宣告失败;
第二步:如果C是一个数组类型,并且数组元素为脊颤昌对象,描述符类似“[Ljava/lang/Integer”的形式按照第一点的规则加载数组元素类型。如果N的描述符如前面所假设的形式,需要加载的类型就是java.lang.Integer,接着由虚拟机生成一个代表次数组维度和元素的数组对象;
第三步:如果上面的步骤没有任何异常,那么C在虚拟机中实际上已经称为一个有效的类或接口了。解析之前还要进行符号验证,确认D是否具有对C的访问权限,如果不具备则会抛出异常。
2、字段解析
对字段表内class_index项中索引的CONSTANT_Class_info符号引用进行解析,也就是字段所属的类或接口的符号引用;
如果解析这个类或符号引用的过程中出现任何异常,都会导致字段符号引用解析的失败;
如果解析成功,接下来沿着它的父类/父接口寻找是否有这个字段;
如果这个过程不出错,则会在找到符合字段的时候返回这个字段的直接引用(如果有会进行权限验证,如果不具备权限则抛出异常)。
3、类方法解析
类方法解析首先也要首先解析出类方法表class_index项中索引的方法所属的类或接口的符号引用;
1)类方法和接口方法符号引用的常量类型定义是分开的,如果在类方法表中索引类是个接口,直接抛出异常;
2)如果通过了第一步,在类中查找是否有简单名称和描述符都与目标匹配的方法,有则返回这个方法的直接引用;
3)如果第二步没找到,则会在类的父类递归查找是否有这个方法,有则返回直接引用,或者在类的接口列表和父接口递归查找,如果存在匹配的方法,说明类是一个抽象类,抛出异常;
4)如果还是没有找到,就是说明该类不存在或不存在在已知路径中,报错抛异常。
4、接口方法解析
接口方法需要先解析出接口方法表的class_index 项中索樱扒引的方法所属的类或接口的符号引用;
如果在class_index发现有名称和描述匹配的方法,则查找成功,直接返回引用,否则就会在其父类接口中递归查找,如果还是找不到或者找到的是类,就直接抛异常。
⑸ 如何设置JVM参数
设置eclipse jvm参数
打开Eclipse 或者 MyEclipse
打开 Windows -> Preferences -> Java -> Installed JREs
在 Default VM Arguments输入框内输入: -Xms512m -Xmx512m
解释:
-Xms是设置java虚拟机的最小分配内存;-Xmx则是最大分配内存;512m为内存空间
一般-Xmx设置为你电脑物理内存的1/4,而把-Xms和 -Xmx设置为一样,
其实你可以设置得更大一些,只要系统能分配足够的内存就可以了,如果设置过大系统会提示你的。
⑹ JVM是如何工作的呢
Java虚拟机
一、什么是Java虚拟机
Java虚拟机是一个想象中的机器,在实际的计算机上通过软件模拟来实现。Java虚拟机有自己想象中的硬件,如处理器、堆栈、寄存器等,还具有相应的指令系统。
1.为什么要使用Java虚拟机
Java语言的一个非常重要的特点就是与平台的无关性。而使用Java虚拟机是实现这一特点的关键。一般的高级语言如果要在不同的平台上运行,至少需要编译成不同的目标代码。而引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用模式Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。
2.谁需要了解Java虚拟机
Java虚拟机是Java语言底层实现的基础,对Java语言感兴趣的人都应对Java虚拟机有个大概的了解。这有助于理解Java语言的一些性质,也有助于使用Java语言。对于要在特定平台上实现Java虚拟机的软件人员,Java语言的编译器作者以及要用硬件芯片实现Java虚拟机的人来说,则必须深刻理解Java虚拟机的规范。另外,如果你想扩展Java语言,或是把其它语言编译成Java语言的字节码,你也需要深入地了解Java虚拟机。
3.Java虚拟机支持的数据类型
Java虚拟机支持Java语言的基本数据类型如下:
byte://1字节有符号整数的补码
short://2字节有符号整数的补码
int://4字节有符号整数的补码
long://8字节有符号整数的补码
float://4字节IEEE754单精度浮点数
double://8字节IEEE754双精度浮点数
char://2字节无符号Unicode字符
几乎所有的Java类型检查都是在编译时完成的。上面列出的原始数据类型的数据在Java执行时不需要用硬件标记。*作这些原始数据类型数据的字节码(指令)本身就已经指出了*作数的数据类型,例如iadd、ladd、fadd和dadd指令都是把两个数相加,其*作数类型别是int、long、 float和double。虚拟机没有给boolean(布尔)类型设置单独的指令。boolean型的数据是由integer指令,包括integer 返回来处理的。boolean型的数组则是用byte数组来处理的。虚拟机使用IEEE754格式的浮点数。不支持IEEE格式的较旧的计算机,在运行 Java数值计算程序时,可能会非常慢。
虚拟机支持的其它数据类型包括:
object//对一个Javaobject(对象)的4字节引用
returnAddress//4字节,用于jsr/ret/jsr-w/ret-w指令
注:Java数组被当作object处理。
虚拟机的规范对于object内部的结构没有任何特殊的要求。在Sun公司的实现中,对object的引用是一个句柄,其中包含一对指针:一个指针指向该object的方法表,另一个指向该object的数据。用Java虚拟机的字节码表示的程序应该遵守类型规定。Java虚拟机的实现应拒绝执行违反了类型规定的字节码程序。Java虚拟机由于字节码定义的限制似乎只能运行于32位地址空间的机器上。但是可以创建一个Java虚拟机,它自动地把字节码转换成64位的形式。从Java虚拟机支持的数据类型可以看出,Java对数据类型的内部格式进行了严格规定,这样使得各种Java虚拟机的实现对数据的解释是相同的,从而保证了Java的与平台无关性和可
移植性。
二、Java虚拟机体系结构
Java虚拟机由五个部分组成:一组指令集、一组寄存器、一个栈、一个无用单元收集堆(Garbage-collected-heap)、一个方法区域。这五部分是Java虚拟机的逻辑成份,不依赖任何实现技术或组织方式,但它们的功能必须在真实机器上以某种方式实现。
1.Java指令集
Java虚拟机支持大约248个字节码。每个字节码执行一种基本的CPU运算,例如,把一个整数加到寄存器,子程序转移等。Java指令集相当于Java程序的汇编语言。
Java指令集中的指令包含一个单字节的*作符,用于指定要执行的*作,还有0个或多个*作数,提供*作所需的参数或数据。许多指令没有*作数,仅由一个单字节的*作符构成。 虚拟机的内层循环的执行过程如下:
do{
取一个*作符字节;
根据*作符的值执行一个动作;
}while(程序未结束)
由于指令系统的简单性,使得虚拟机执行的过程十分简单,从而有利于提高执行的效率。指令中*作数的数量和大小是由*作符决定的。如果*作数比一个字节大,那么它存储的顺序是高位字节优先。例如,一个16位的参数存放时占用两个字节,其值为:
第一个字节*256+第二个字节字节码指令流一般只是字节对齐的。指令tableswitch和lookup是例外,在这两条指令内部要求强制的4字节边界对齐。
2.寄存器
Java虚拟机的寄存器用于保存机器的运行状态,与微处理器中的某些专用寄存器类似。
Java虚拟机的寄存器有四种:
pc:Java程序计数器。
optop:指向*作数栈顶端的指针。
frame:指向当前执行方法的执行环境的指针。
vars:指向当前执行方法的局部变量区第一个变量的指针。
Java虚拟机
Java虚拟机是栈式的,它不定义或使用寄存器来传递或接受参数,其目的是为了保证指令集的简洁性和实现时的高效性(特别是对于寄存器数目不多的处理器)。
所有寄存器都是32位的。
3.栈
Java虚拟机的栈有三个区域:局部变量区、运行环境区、*作数区。
(1)局部变量区 每个Java方法使用一个固定大小的局部变量集。它们按照与vars寄存器的字偏移量来寻址。局部变量都是32位的。长整数和双精度浮点数占据了两个局部变量的空间,却按照第一个局部变量的索引来寻址。(例如,一个具有索引n的局部变量,如果是一个双精度浮点数,那么它实际占据了索引n和n+1所代表的存储空间。)虚拟机规范并不要求在局部变量中的64位的值是64位对齐的。虚拟机提供了把局部变量中的值装载到*作数栈的指令, 也提供了把*作数栈中的值写入局部变量的指令。
(2)运行环境区 在运行环境中包含的信息用于动态链接,正常的方法返回以及异常传播。
·动态链接
运行环境包括对指向当前类和当前方法的解释器符号表的指针,用于支持方法代码的动态链接。方法的class文件代码在引用要调用的方法和要访问的变量时使用符号。动态链接把符号形式的方法调用翻译成实际方法调用,装载必要的类以解释还没有定义的符号,并把变量访问翻译成与这些变量运行时的存储结构相应的偏移地址。动态链接方法和变量使得方法中使用的其它类的变化不会影响到本程序的代码。
·正常的方法返回
如果当前方法正常地结束了,在执行了一条具有正确类型的返回指令时,调用的方法会得到一个返回值。执行环境在正常返回的情况下用于恢复调用者的寄存器,并把调用者的程序计数器增加一个恰当的数值,以跳过已执行过的方法调用指令,然后在调用者的执行环境中继续执行下去。
·异常和错误传播
异常情况在Java中被称作Error(错误)或Exception(异常),是Throwable类的子类,在程序中的原因是:①动态链接错,如无法找到所需的class文件。②运行时错,如对一个空指针的引用
·程序使用了throw语句。
当异常发生时,Java虚拟机采取如下措施:
·检查与当前方法相联系的catch子句表。每个catch子句包含其有效指令范围,能够处理的异常类型,以及处理异常的代码块地址。
·与异常相匹配的catch子句应该符合下面的条件:造成异常的指令在其指令范围之内,发生的异常类型是其能处理的异常类型的子类型。如果找到了匹配的catch子句,那么系统转移到指定的异常处理块处执行;如果没有找到异常处理块,重复寻找匹配的catch子句的过程,直到当前方法的所有嵌套的 catch子句都被检查过。
·由于虚拟机从第一个匹配的catch子句处继续执行,所以catch子句表中的顺序是很重要的。因为Java代码是结构化的,因此总可以把某个方法的所有的异常处理器都按序排列到一个表中,对任意可能的程序计数器的值,都可以用线性的顺序找到合适的异常处理块,以处理在该程序计数器值下发生的异常情况。
·如果找不到匹配的catch子句,那么当前方法得到一个"未截获异常"的结果并返回到当前方法的调用者,好像异常刚刚在其调用者中发生一样。如果在调用者中仍然没有找到相应的异常处理块,那么这种错误传播将被继续下去。如果错误被传播到最顶层,那么系统将调用一个缺省的异常处理块。
(3)*作数栈区 机器指令只从*作数栈中取*作数,对它们进行*作,并把结果返回到栈中。选择栈结构的原因是:在只有少量寄存器或非通用寄存器的机器(如Intel486)上,也能够高效地模拟虚拟机的行为。*作数栈是32位的。它用于给方法传递参数,并从方法接收结果,也用于支持*作的参数,并保存*作的结果。例如,iadd指令将两个整数相加。相加的两个整数应该是*作数栈顶的两个字。这两个字是由先前的指令压进堆栈的。这两个整数将从堆栈弹出、相加,并把结果压回到*作数栈中。
每个原始数据类型都有专门的指令对它们进行必须的*作。每个*作数在栈中需要一个存储位置,除了long和double型,它们需要两个位置。* 作数只能被适用于其类型的*作符所*作。例如,压入两个int类型的数,如果把它们当作是一个long类型的数则是非法的。在Sun的虚拟机实现中,这个限制由字节码验证器强制实行。但是,有少数*作(*作符pe和swap),用于对运行时数据区进行*作时是不考虑类型的。
4.无用单元收集堆
Java的堆是一个运行时数据区,类的实例(对象)从中分配空间。Java语言具有无用单元收集能力:它不给程序员显式释放对象的能力。Java不规定具体使用的无用单元收集算法,可以根据系统的需求使用各种各样的算法。
5.方法区
方法区与传统语言中的编译后代码或是Unix进程中的正文段类似。它保存方法代码(编译后的java代码)和符号表。在当前的Java实现中,方法代码不包括在无用单元收集堆中,但计划在将来的版本中实现。每个类文件包含了一个Java类或一个Java界面的编译后的代码。可以说类文件是Java 语言的执行代码文件。为了保证类文件的平台无关性,Java虚拟机规范中对类文件的格式也作了详细的说明。其具体细节请参考Sun公司的Java虚拟机规范。
内容来源于网上。
⑺ JVM性能调优指南(一)
-help
-server -client
-version -showversion
-cp -classpath
调整为 完全解释执行 编译模式:
调整为 编译执行 编译模式:
最后历友一行的 mixed mode 表明JVM默认使用的编译模式是 混合模式
使用最多的空烂裤一种参数类型
格式: -XX:[+/-] <name> 表示启用或者禁用name属性
比如:
-XX:+UseConcMarkSweepGC 表示启用CMS垃圾回收器
-XX:+UseG1GC 表示启用G1垃圾回收器
格式: -XX:<name> = <value> 表示name属性的值为value
比如:
-XX:MaxGCPauseMillis=500 表示GC最大停顿时间是500毫秒
-XX:GCTimeRatio=19 表示...
虽然1以X开头,但是不是X类型参数,而是XX类型的参数
如查看JVM版本信息: java -XX:+PrintFlagsFinal -version > ~/version.txt
注: = 表示默认值, =: 表示修改后的值
关于jps等命令的详解,可参考此文档 https://docs.oracle.com/javase/8/docs/technotes/tools/unix/index.html
如查看一个java进程id为9723的tomcat服务最大堆内存大小
查看一个进程的所有运行时参数:
Non-default VM flags 表示手动赋值过的参数,其中有些是tomcat设置的
Command line :与 Non-default VM flags
查看垃圾回收器信息
格式: jstat -class 进程id 每隔多少毫秒 一共输出多少次
如:查看斗简一个进程id为29159的java进程,每隔1s输出,一共输出10次
要查看一个java进程的垃圾收集器信息,可使用 jstat -gc 进程id 每隔多少毫秒 一共输出多少次
S0C : Current survivor space 0 capacity (kB). 表示survivor 0区的总大小
S1C : Current survivor space 1 capacity (kB). 表示survivor 1区的总大小
S0U : Survivor space 0 utilization (kB). 表示survivor 0区使用了的大小
S1U : Survivor space 1 utilization (kB). 表示survivor 1区使用了的大小
EC : Current eden space capacity (kB). 表示eden区总大小
EU : Eden space utilization (kB). 表示eden区使用了的大小
OC : Current old space capacity (kB). 表示old区总大小
OU : Old space utilization (kB). 表示old区使用了的大小
MC : Metaspace capacity (kB). 表示Metaspace区总大小
MU : Metacspace utilization (kB). 表示Metaspace区使用了的大小
CCSC : Compressed class space capacity (kB). 表示压缩类空间总量
CCSU : Compressed class space used (kB). 表示压缩类空间使用量
YGC : Number of young generation garbage collection events. 表示Young GC的次数
YGCT : Young generation garbage collection time. 表示Young GC的时间
FGC : Number of full GC events. 表示full GC的次数
FGCT : Full garbage collection time. 表示full GC的时间
GCT : Total garbage collection time. 表示总的 GC的时间
模拟内存溢出:
设置启动参数:
启动application,发现出现内存溢出
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=./
格式: jmap -mp:format=b,file=路径/heap.hprof 进程id
其他命令: jmap -heap 进程id 查看堆信息
右键查看com.imooc.monitor_tuning.chapter2.User的强引用
也可以查看对象树:
格式: jstack 进程id
访问/loop端点三次,然后使用top命令:
然后在导出的7930.txt文件中找到2037
访问/loop端点,制造死循环,使用jstack命令导出线程堆栈信息:
最后一行已提示:Found 1 deadlock
相关资料:
jdk8工具集
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/index.html
Troubleshooting
https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/
jps
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jps.html
jinfo
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jinfo.html
jstat
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jstat.html
jmap:
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jmap.html
mat:
http://www.eclipse.org/mat/downloads.php
jstack:
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jstack.html
java线程的状态
https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr034.html
java线程状态转化:
https://mp.weixin.qq.com/s/GsxeFM7QWuR--Kbpb7At2w
死循环导致CPU负载高
https://blog.csdn.net/goldenfish1919/article/details/8755378
正则表达式导致死循环:
https://blog.csdn.net/goldenfish1919/article/details/49123787
⑻ “JVM”调优参数总结
因此我们一般设罩滑置-Xms、-Xmx这两个参数相等,可以避蚂闷竖免在每次GC 后动态调整堆的大小带来的影响。
吞吐量和停顿时间是互斥的。 对于后端服务(比如后台计算任务),吞吐量优先考虑(并行垃圾回收);
对于前端应用,RT响应闷大时间优先考虑,减少垃圾收集时的停顿时间,适用场景是Web系统(并发垃圾回收)