加入收藏 | 设为首页 | 会员中心 | 我要投稿 PHP编程网 - 黄冈站长网 (http://www.0713zz.com/)- 数据应用、建站、人体识别、智能机器人、语音技术!
当前位置: 首页 > 综合聚焦 > 资源网站 > 空间 > 正文

对JVM还有什么不懂的?带你深入浅出JVM!

发布时间:2019-10-14 07:29:56 所属栏目:空间 来源:java互联网架构
导读:副标题#e# JVM JVM = 类加载器(classloader) + 执行引擎(execution engine) + 运行时数据区域(runtime data area) 下面这幅图展示了一个典型的JVM(符合JVM Specification Java SE 7 Edition)所具备的关键内部组件。 组件中的多线程处理 多线程处理或自由线
副标题[/!--empirenews.page--]

 对JVM还有什么不懂的?带你深入浅出JVM!

JVM

JVM = 类加载器(classloader) + 执行引擎(execution engine) + 运行时数据区域(runtime data area)

下面这幅图展示了一个典型的JVM(符合JVM Specification Java SE 7 Edition)所具备的关键内部组件。

对JVM还有什么不懂的?资深架构师一篇文章带你深入浅出JVM!

组件中的多线程处理

多线程处理”或“自由线程处理”指的是一个程序同时执行多个操作线程的能力。 作为多线程应用程序的一个示例,某个程序在一个线程上接收用户输入,在另一个线程上执行多种复杂的计算,并在第三个线程上更新数据库。 在单线程应用程序中,用户可能会花费时间等待计算或数据库更新完成。 而在多线程应用程序中,这些进程可以在后台进行,因此不会浪费用户时间。 多线程处理可以是组件编程中的一个非常强大的工具。通过编写多线程组件,您可以创建在后台执行复杂计算的组件,它们允许用户界面 (UI) 在计算的过程中自由地响应用户输入。 虽然多线程处理是一个强大的工具,但是要将其正确应用却比较困难。 未能正确实现的多线程代码可能降低应用程序性能,或甚至导致应用程序冻结。 下列主题将向您介绍多线程编程的一些注意事项和最佳做法。.NET Framework 提供几个在组件中进行多线程处理的选项。 System.Threading 命名空间中的功能是一个选项。 基于事件的异步模式是另一个选项。 BackgroundWorker 组件是对异步模式的实现;它提供封装在组件中以便于使用的高级功能。

JVM内存管理机制

(1)内存区域与内存溢出异常

(2)垃圾收集器与内存分配策略

(3)虚拟机性能监控与故障处理工具

JVM调优

1.JVM执行子系统

(1)类文件结构

(2)类加载机制

(3)字节码执行引擎

2.程序编译与代码优化

(1)编译期优化

(2)运行期优化

3.实战调优案例与解决方法

对JVM还有什么不懂的?资深架构师一篇文章带你深入浅出JVM!

JVM系统线程

如果你用jconsole或者任何其他的debug工具查看,可能会看到有许多线程在后台运行。这些运行着的后台线程不包含主线程,主线程是基于执行publicstatic void main(String[]) 的需要而被创建的。而这些后台线程都是被主线程所创建。在HotspotJVM中主要的后台系统线程,见下表:

对JVM还有什么不懂的?资深架构师一篇文章带你深入浅出JVM!

单个线程

每个线程的一次执行都包含如下的组件

程序计数器(PC)

除非当前指令或者操作码是原生的,否则当前指令或操作码的地址都需要依赖于PC来寻址。如果当前方法是原生的,那么该PC即为undefined。所有的CPU都有一个PC,通常PC在每个指令执行后被增加以指向即将执行的下一条指令的地址。JVM使用PC来跟踪正在执行的指令的位置。事实上,PC被用来指向methodarea的一个内存地址。

原生栈

不是所有的JVM都支持原生方法,但那些支持该特性的JVM通常会对每个线程创建一个原生方法栈。如果对JVM的JNI(JavaNative Invocation)采用c链接模型的实现,那么原生栈也将是一个C实现的栈。在这个例子中,原生栈中参数的顺序 、返回值都将跟通常的C程序相同。一个原生方法通常会对JVM产生一个回调(这依赖于JVM的实现)并执行一个Java方法。这样一个原生到Java的调用发生在栈上(通常在Java栈),与此同时线程也将离开原生栈,通常在Java栈上创建一个新的frame。

每个线程都有属于它自己的栈,用于存储在线程上执行的每个方法的frame。栈是一个后进先出的数据结构,这可以使得当前正在执行的方法位于栈的顶部。对于每个方法的执行,都会有一个新的frame被创建并被入栈到栈的顶部。当方法正常的返回或在方法执行的过程中遇到未捕获的异常时frame会被出栈。栈不会被直接进行操作,除了push/ pop frame 对象。因此可以看出,frame对象可能会被分配在堆上,并且内存也没必要是连续的地址空间(请注意区分frame的指针跟frame对象)。

栈的限制

一个栈可以是动态的或者是有合适大小的。如果一个线程要求更大的栈,那么将抛出StackOverflowError异常;如果一个线程要求新创建一个frame,又没有足够的内存空间来分配,将会抛出OutOfMemoryError异常。

Frame

对于每一个方法的执行,一个新frame会被创建并被入栈到栈顶。当方法正常返回或在方法执行的过程中遇到未捕获的异常,frame会被出栈。

局部变量数组

局部变量数组包含了在方法执行期间所用到的所有的变量。包含一个对this的引用,所有的方法参数,以及其他局部定义的变量。对于类方法(比如静态方法),方法参数的存储索引从0开始;而对于实例方法,索引为0的槽都为存储this指针而保留。

操作数栈

操作数栈在字节码指令被执行的过程中使用。它跟原生CPU使用的通用目的的寄存器类似。大部分的字节码都把时间花费在跟操作数栈打交道上,通过入栈、出栈、复制、交换或者执行那些生产/消费值的操作。对字节码而言,那些在局部变量数组和操作数栈之间移动值的指令是非常频繁的。

动态链接

每个frame都包含一个对运行时常量池的引用。该引用指向将要被执行的方法所属的类的常量池。该引用也用于辅助动态链接。

当一个Java类被编译时,所有对存储在类的常量池中的变量以及方法的引用都被当做符号引用。一个符号引用仅仅只是一个逻辑引用而不是最终指向物理内存地址的引用。JVM的实现可以选择解析符号引用的时机,该时机可以发生在当类文件被验证后、被加载后,这称之eager或静态分析;不同的是它也可以发生在当符号引用被首次使用的时候,称之为lazy或延迟分析。但JVM必须保证:解析发生在每个引用被首次使用前,同时在该时间点,如果遇到分析错误能够抛出异常。绑定是一个处理过程,它将被符号引用标识的字段、方法或类替换为一个直接引用。这个处理过程只发生一次,因为符号引用需要被完全替换。如果一个符号引用关联着一个类,而该类还没有被解析,那么该类也会被立即加载。每个直接引用都被以偏移的方式存储,该存储结构关联着变量或方法的运行时位置。

线程之间共享

堆中某个节点的值总是不大于或不小于其父节点的值;

堆总是一棵完全二叉树。

将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。常见的堆有二叉堆、斐波那契堆等。

堆的定义如下:n个元素的序列{k1,k2,ki,…,kn}当且仅当满足下关系时,称之为堆。

(ki <= k2i,ki <= k2i+1)或者(ki >= k2i,ki >= k2i+1), (i = 1,2,3,4...n/2)

(编辑:PHP编程网 - 黄冈站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

推荐文章
    热点阅读