学习java的人都知道,java是一个半编译语言,可运行于多个平台,如Windows,Mac OS,及其他多种UNIX版本的系统。总之,开发起来比c,c++简便许多。大家都听说过JVM,以及面试的时候也经常会问到与此相关的问题, 建议大家一字一字的阅读,不懂多问,大神们多提提意见。好了,废话不多说,引入正题。
JDK 1.8同JDK 1.7 最大的区别是:元数据取代了永久代.元空间的本质和永久代类似,都是对JVM规范中的方法区的实现.其元空间和永久代之间的最大区别在于:元数据空间不在虚拟机中,而是在本地内存中
首先先要了解使用到JVM专用的词汇
- OOM异常(OutOfMemoryError):当前占用的内存加上我们申请的内存资源超过了
虚拟机的最大内存限制就会抛出的Out Of Memory异常
- 堆内存区域
- Xmx value 指定最大的堆大小
- Xms value 指定初始的最小堆大小
- XX:NewSize = value 指定新生代的大小
- XX:NewRatio = value 老年代与新生代的大小比例。默认情况下,这个 比例是2,也就是说老年代是新生代的2倍大。老年代过大的时候,Full GC的时间会很长;老年代过小,则很容易触发Full GC,Full GC频率过高,这就是这个参数会造成的影响。
- XX:SurvivorRation = value . 设置Eden与Srivivor的大小比例,如果该值为8,代表一个Survivor是Eden的1/8,是整个新生代的1/10。
1、程序计数器(Program Counter Register)
在JVM规范中,每个线程都会有专属的程序计数器,就像一个人只能有一个老婆的道理一样,但这是一块比较小的内存空间,存储当前线程正在执行的Java方法的JVM指令地址,也就是我们.class编译后的字节码的行号。熟悉汇编的都应该知道这个的原理。如果正在执行Native方法,则这个计数器为空。注意:该内存区域是唯一一个在Java虚拟机规范中没有规定任何OOM情况的内存区域。
2、Java虚拟机栈(Java Virtal Machine Stack)
也是属于线程私有区域,每个线程在创建的时候都会创建一个虚拟机栈,生命周期与线程一致,线程退出时,线程的虚拟机栈也回收。虚拟机栈内部保持一个个的栈帧,每次方法调用都会进行压栈,JVM对栈帧的操作只有出栈和压栈两种,方法调用结束时会进行出栈操作。
3、本地方法栈(Native Method Stack)
虚拟机栈类似,本地方法栈是在调用本地方法时使用的栈,每个线程都有一个本地方法栈。
如果想要了解虚拟机栈和本地方法栈的可以查看一下
虚拟机栈和本地方法栈到底有什么区别??
本地方法栈native到底是什么???
4、堆(Heap)
几乎所有创建的Java对象实例,都是被直接分配到堆上的。堆被所有的线程所共享,在堆上的区域,会被垃圾回收器做进一步划分,例如新生代、老年代的划分。Java虚拟机在启动的时候,可以使用“Xmx”之类的参数指定堆区域的大小。
不懂堆和栈的后续我也会出一篇介绍
5、方法区(Method Area)
方法区与堆一样,也是所有的线程所共享,存储被虚拟机加载的元(Meta)数据,包括类信息、常量、静态变量、即时编译器编译后的代码等数据。这里需要注意的是运行时常量池也在方法区中。
6、运行时常量池(Run-Time Constant Pool)
这是方法区的一部分,受到方法区内存的限制,当常量池无法再申请到内存时,会抛出OutOfMemoryError(OOM)异常
运行时常量池详解
7、直接内存(Direct Memory)
直接内存并不属于Java规范规定的属于Java虚拟机运行时数据区的一部分。Java的NIO可以使用Native方法直接在java堆外分配内存,使用DirectByteBuffer对象作为这个堆外内存的引用。
直接内存并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域,但是这部分内存也被频繁地使用,而且也可能导致OutOfMemoryError异常出现。
说完这些,又想继续说 垃圾回收机制了。后续会写