网站在服务器,wordpress浮动插件,阿里指数查询入口,网站建设主持词一、JVM简介 JVM#xff0c;即Java虚拟机#xff08;Java Virtual Machine#xff09;#xff0c;一种能够运行Java bytecode的虚拟机#xff0c;是Java实现跨平台的基础。 引入Java语言虚拟机后#xff0c;Java语言在不同平台上运行时不需要重新编译。Java语言使用Java虚…一、JVM简介 JVM即Java虚拟机Java Virtual Machine一种能够运行Java bytecode的虚拟机是Java实现跨平台的基础。 引入Java语言虚拟机后Java语言在不同平台上运行时不需要重新编译。Java语言使用Java虚拟机屏蔽了与具体平台相关的信息使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码字节码就可以在多种平台上不加修改地运行。Java虚拟机在执行字节码时把字节码解释成具体平台上的机器指令执行。这就是Java的能够“一次编译到处运行”的原因。 二、JVM分区 Java虚拟机在执行Java程序的过程中会把它管辖的内存划分为若干个不同的数据区域。如下图所示 1程序计数器 程序计数器Program Counter Register程序计数器是一个比较小的内存区域用于指示当前线程所执行的字节码执行到了第几行可以理解为是当前线程的行号指示器。字节码解释器在工作时会通过改变这个计数器的值来取下一条语句指令。每个程序计数器只用来记录一个线程的行号所以它是线程私有一个线程就有一个程序计数器的。 如果程序执行的是一个Java方法则计数器记录的是正在执行的虚拟机字节码指令地址如果正在执行的是一个本地native由C语言编写完成方法则计数器的值为Undefined由于程序计数器只是记录当前指令地址所以不存在内存溢出的情况因此程序计数器也是所有JVM内存区域中唯一一个没有定义OutOfMemoryError的区域。 2虚拟机栈 虚拟机栈JVM Stack一个线程的每个方法在执行的同时都会创建一个栈帧Statck Frame栈帧中存储的有局部变量表、操作栈、动态链接、方法出口等当方法被调用时栈帧在JVM栈中入栈当方法执行完成时栈帧出栈。 局部变量表中存储着方法的相关局部变量包括各种基本数据类型对象的引用返回地址等。在局部变量表中只有long和double类型会占用2个局部变量空间Slot对于32位机器一个Slot就是32个bit其它都是1个Slot。需要注意的是局部变量表是在编译时就已经确定好的方法运行所需要分配的空间在栈帧中是完全确定的在方法的生命周期内都不会改变。 虚拟机栈中定义了两种异常如果线程调用的栈深度大于虚拟机允许的最大深度则抛出StatckOverFlowError栈溢出不过多数Java虚拟机都允许动态扩展虚拟机栈的大小(有少部分是固定长度的)所以线程可以一直申请栈直到内存不足此时会抛出OutOfMemoryError内存溢出。 每个线程对应着一个虚拟机栈因此虚拟机栈也是线程私有的。 3本地方法栈 本地方法栈Native Method Statck本地方法栈在作用、运行机制、异常类型等方面都与虚拟机栈相同唯一的区别是虚拟机栈是执行Java方法的而本地方法栈是用来执行native方法的在很多虚拟机中如Sun的JDK默认的HotSpot虚拟机会将本地方法栈与虚拟机栈放在一起使用。 本地方法栈也是线程私有的。 4堆区 堆区Heap堆区是理解Java GC机制最重要的区域没有之一。在JVM所管理的内存中堆区是最大的一块堆区也是Java GC机制所管理的主要内存区域堆区由所有线程共享在虚拟机启动时创建。堆区的存在是为了存储对象实例原则上讲所有的对象都在堆区上分配内存不过现代技术里也不是这么绝对的也有栈上直接分配的。 一般的根据Java虚拟机规范规定堆内存需要在逻辑上是连续的在物理上不需要在实现时可以是固定大小的也可以是可扩展的目前主流的虚拟机都是可扩展的。如果在执行垃圾回收之后仍没有足够的内存分配也不能再扩展将会抛出OutOfMemoryError异常。 5方法区 方法区Method Area在Java虚拟机规范中将方法区作为堆的一个逻辑部分来对待但事实上方法区并不是堆Non-Heap另外不少人的博客中将Java GC的分代收集机制分为3个代青年代老年代永久代这些作者将方法区定义为“永久代”这是因为对于之前的HotSpot Java虚拟机的实现方式中将分代收集的思想扩展到了方法区并将方法区设计成了永久代。不过除HotSpot之外的多数虚拟机并不将方法区当做永久代HotSpot本身也计划取消永久代。本文中由于笔者主要使用Oracle JDK6.0因此仍将使用永久代一词。 方法区是各个线程共享的区域用于存储已经被虚拟机加载的类信息即加载类时需要加载的信息包括版本、field、方法、接口等信息、final常量、静态变量、编译器即时编译的代码等。 方法区在物理上也不需要是连续的可以选择固定大小或可扩展大小并且方法区比堆还多了一个限制可以选择是否执行垃圾收集。一般的方法区上执行的垃圾收集是很少的这也是方法区被称为永久代的原因之一HotSpot但这也不代表着在方法区上完全没有垃圾收集其上的垃圾收集主要是针对常量池的内存回收和对已加载类的卸载。 在方法区上进行垃圾收集条件苛刻而且相当困难效果也不令人满意所以一般不做太多考虑可以留作以后进一步深入研究时使用。 在方法区上定义了OutOfMemoryError异常在内存不足时抛出。 运行时常量池Runtime Constant Pool是方法区的一部分用于存储编译期就生成的字面常量、符号引用、翻译出来的直接引用符号引用就是编码是用字符串表示某个变量、接口的位置直接引用就是根据符号引用翻译出来的地址将在类链接阶段完成翻译运行时常量池除了存储编译期常量外也可以存储在运行时间产生的常量比如String类的intern()方法作用是String维护了一个常量池如果调用的字符“abc”已经在常量池中则返回池中的字符串地址否则新建一个常量加入池中并返回地址。 6直接内存 直接内存Direct Memory直接内存并不是JVM管理的内存可以这样理解直接内存就是JVM以外的机器内存比如你有4G的内存JVM占用了1G则其余的3G就是直接内存JDK中有一种基于通道Channel和缓冲区 Buffer的内存分配方式将由C语言实现的native函数库分配在直接内存中用存储在JVM堆中的DirectByteBuffer来引用。 由于直接内存收到本机器内存的限制所以也可能出现OutOfMemoryError的异常。 参考资料https://segmentfault.com/a/1190000002579346