程序计数器(线程私有)
它表示什么??
当前字节码执行的行号指示器。如果线程当前执行的是一个java方法,程序计数器指向的是当前字节码执行的指令的地址。如果执行的书native方法,这个计数器为空(Undefined)。
这个区域的异常情况??
这个区域是唯一一个在《java虚拟机规范》中没有规定任何OOM的区域。
java虚拟机栈(线程私有)
栈帧存储了什么??
用于存储局部变量表(存储了编译器可知的个中java基本数据类型,引用类型,returnAddress类型(指向了一条字节码指令的类型),这些数据类型在局部变量表中的存储空间以局部变量槽Slot(数据类型只会以slot的数量计算,至于一个slot栈多少个bit,这个由jvm自行决定)来表示。其中64位长度的double,long会占用两个slot,其余数据类型为1个slot。局部变量表的内存空间在编译期间就完成了分配,进入一个方法的时候,这个方法需要在栈帧中分配多大的局部变量空间是完全确定的,不会在运行期间改变。),操作数栈,动态连接,方法出口等信息。
这个区域存在的异常情况??
当出现栈超过所允许的深度,StackOverFlowError异常。
HotSpot的虚拟机的栈是不允许动态扩展的(以前的Classic是可以动态扩展的)。所以只要申请成功了就不会出现OOM,但是申请失败的情况下还是会出现OOM的。
生命周期??
它的生命周期和线程同步。
执行过程??
当一个方法执行的时候,就会生成一个栈帧,压入栈。
方法执行完成的时候,pop出去这个栈帧。
本地方法栈
和java虚拟机栈作用是一样的。
区别在于java虚拟机栈执行的是java方法服务,而本地方法栈执行的是native方法服务。
java堆(Heap)(线程共享)
可以说,这里是java程序最大的一块区域。
Heap存储了什么??
存储对象,几乎所有的对象都在这里。这里说几乎,是因为现在的逃逸分析,可以使编译期间的对象分配,分配到其他地方。(标量替换,栈上分配等)。
存储空间??
现在基本都基于分代收集理论设计的。(但是这里的新生代,老年代,永久代,Eden空间等,并不是java堆的内存细分。)
java堆可以处在物理上不连续的内存空间,但在逻辑上应该被视为连续的。
异常情况??
当没有内存进行实例分配,而且无法再扩展的时候就会OOM。
方法区(线程共享)
它在什么位置?
java规范中其实它是定义在堆中的一块逻辑部分,物理上可以不连续,可以选择固定大小,或者可扩展,甚至还可以不实现垃圾收集。(相对来说,这部分一般只是进行常量回收和类型卸载,GC比较不理想)
和永久代的区别??
在HotSpot中,方法区只是利用永久代来实现,在一些其他的jvm,并不是这样实现的,所以严格来说,方法区并不是“永久的”。
之后JDK的发展中,已经利用了本地内存来实现方法区了。JDK8的时候,有了元空间的概念,将jdk永久代的东西全部移过来了。
存储什么??
已经被加载的类型信息,常量,静态变量,即时编译后的代码缓存等。
异常情况:
无法满足新的内存分配的时候,也会出现OOM。
运行时常量池
存储位置??
是方法区的一部分。
Class文件除了累的版本,字段,方法,接口等描述信息外,还有意向信息是常量池表,用于存放编译期间生成的个中字面量与符号引用(这部分将在类加载后存放到方法区的运行时常量池中)。
而且这部分是动态的,并不是只有编译期产生的,运行期间也可以产生然后放进运行时常量池(String.intern())。
异常情况:OOM。
直接内存
这部分并不是jvm运行时数据区的一部分。也不是规范中定义的内存区域,但是却频繁出现。
jdk1。4出现了NIO,他可以通过native直接分配堆外内存。然后通过一个存储在堆中的DirectByteBuffer对象作为这块区域的引用进行操作。这样子,可以避免在java堆和native堆中来回复制数据。
异常情况:过大也会导致OOM。
网友评论