您的位置:首页 > 编程语言 > Java开发

0010 Java JVM虚拟机7块内存区划分【入门】

2014-12-18 22:25 381 查看
顺口溜:器池堆,栈栈区区

弃池堆,站站曲曲(一离开卫生间,肚子疼的站不起身)



Java中内存的管理机制是通过JVM来自动管理的。了解JVM的基础原理有利于进一步理解Java。



我们首先要了解java内存的分配机制,在java虚拟机规范里,JVM被分为7个内存区域。

虚拟机规范中的7个内存区域分别是三个线程私有的和四个线程共享的内存区。



线程私有的内存区域:线程私有的内存区域与线程具有相同的生命周期,它们分别是:指令计数器、线程栈和本地线程栈。

四个共享区:四个共享区是所有线程共享的,在JVM启动时就会分配,分别是:方法区、 常量池、直接内存区和堆(即我们通常所说的JVM的内存分为堆和栈中的堆,后者就是前面的线程栈)。

1 、指令计数器。

我们都知道java的多线程是通过JVM切换时间片运行的,因此每个线程在某个时刻可能在运行也可能被挂起,那么当线程挂起之后,JVM再次调度它时怎么知道该线程要运行那条字节码指令呢?这就需要一个与该线程相关的内存区域记录该线程下一条指令,而指令计数器就是实现这种功能的内存区域。有多少线程在编译时是不确定的,因此该区域也没有办法在编译时分配,只能在创建线程时分配,所以说该区域是线程私有的,该区域只是指令的计数,占用的空间非常少,所以虚拟机规范中没有为该区域规定OutofMemoryError。

2、线程栈(虚拟机栈)。

每个栈空间的默认大小为0.5M,在1.7里调整为1M,每调用一次方法就会压入一个栈帧,如果压入的栈帧深度过大,即方法调用层次过深,就会抛出StackOverFlow,,SOF最常见的场景就是递归中,当递归没办法退出时,就会抛此异常,Hotspot提供了参数设置改区域的大小,使用-Xss:xxK,就可以修改默认大小。

3、本地线程栈。

该区域主要是给调用本地方法的线程分配的,该区域和线程栈的最大区别就是,在该线程的申请的内存不受GC管理,需要调用者自己管理,JDK中的Math类的大部分方法都是本地方法,一个值得注意的问题是,在执行本地方法时,并不是运行字节码,所以之前所说的指令计数器是没法记录下一条字节码指令的,当执行本地方法时,指令计数器置为undefined。

本地方法栈与线程栈所发挥的作用是非常相似的,其区别在于线程栈为虚拟机执行Java方法服务,而本地方方法栈是为虚拟机使用到的Native方法服务。

4、方法区。

这块区域是用来存放JVM装载的class的类信息,包括:类的方法、静态变量、类型信息(接口/父类),我们使用反射技术时,所需的信息就是从这里获取的。

一般来说这个区域的内存回收目标是针对常量池的回收和对类型的卸载。

5、常量池。

变量用final修饰,不能再修改它的值,所以就成为常量,而这常量将会存放在常量区,这些常量在编译时就知道占用空间的大小,但并不是说明该区域编译就固定了,运行期也可以修改常量池的大小,典型的场景是在使用String时,你可以调用String的 intern(),JVM会判断当前所创建的String对象是否在常量池中,若有,则从常量区取,否则把该字符放入常量池并返回,这时就会修改常量池的大小(常量的大小是不可改变的)。

6、直接内存区。

直接内存区并不是JVM可管理的内存区。在JDK1.4中提供的NIO中,实现了高效的R/W操作,这种高效的R/W操作就是通过管道机制实现的,而管道机制实际上使用了本地内存,这样就避免了从本地源文件复制JVM内存,再从JVM复制到目标文件的过程,直接从源文件复制到目标文件,JVM通过DirectByteBuffer操作直接内存。

==?在JDK1.4中新加入了NIO类,引入了一种基于通道与缓冲区的I/O方式,它可以使用Native函数直接分配堆外内存,然后通过一个存储在Java堆里面的DirectByteBuffer对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在Java堆和Native堆中来回复制数据。来

7、堆。

堆是JVM中的最常见的、最为熟知的内存区,我们通常所说的GC主要就是在这块区域中进行的,所有的java对象都在这里分配,这也是JVM中最大的内存区域,被所有线程共享,成千上万的对象在这里创建,也在这里被销毁。

对象访问

在Java语言中,对象的访问时如何进行的?即使最普通的对象访问也会涉及到Java堆、Java栈、方法区这三个最重要内存区域,如下面这段代码:

Object obj = new Object();

假设这句代码出现在方法体中,那“Object obj”这部分的语义将会反映到Java栈的本地变量表中,作为一个reference类型出现。而“new Object()”这部分语义将会反映到Java堆中,形成一块存储了Object类型所有实例数据的结构化内存。在Java堆中还必须包含能查找到此对象类型数据(如对象类型,父类,实现的接口,方法等)的地址信息,这些类型数据则存储在方法区中。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: