java虚拟机之一java内存区域

说在虚拟机篇开头的话,其实把这些文章复制粘贴一点用也没有,最主要的是要理解和实践。尤其是实践。

这一篇文章中提到的相关溢出异常,如何让程序出现溢出异常的实践,会在后面的章节说明。

1.java虚拟机在执行java程序时,会把内存分为若干个数据区域。

这些数据区域包括:程序计数器,java虚拟机栈,本地方法栈,方法区和堆

2.程序计数器

这一块内存空间较小,它记录的是正在执行的Class字节码指令的地址。

当然它只记录java方法,如果是Native方法,则记录值为空。

这一块内存空间是唯一一块没有“内存溢出异常(OutofMemoryError)”的区域。

java多线程互相切换后之所以还能回到原来的执行程序继续执行,就是因为程序计数器,它的原理如下:

java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,在一个确定的时刻,一个处理器只会执行一条指令。而每条线程都有自己独立的计数器,当线程切换时,虚拟机会找到当前线程的计数器,根据计数器记录的字节码指令的地址,找到相应程序继续执行。

3.java虚拟机栈

这块内存空间描述的是java方法的内存模型。

每个java方法在执行时,都会创建一个栈桢,用于存储方法的局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用到执行完成的过程,其实就是对应着一个栈桢在虚拟机栈中从入栈到出栈的过程。

我们通常所讲的“堆内存”和“栈内存”,其中的“栈内存”其实就是指的这个虚拟机栈或者说是虚拟机栈中的局部变量表部份。

这一块的内存也是线程私有的,这也解释了为什么方法内部和线程封闭的线程是线程安全的。关于线程安全可以阅读我的线程方面的文章。

如果栈的深度超过虚拟机所规定的深度,则报“栈溢出异常(StackOverflowError)”,这里所谓的深度指的是方法里面调用方法,嵌套调用的方法越多,深度越深。

如果虚拟机栈可以动态扩展,当扩展到无法申请足够的内存,则会报“内存溢出异常(OutofMemoryError)”。

4.本地方法栈

这个和java虚拟机栈是一样的,唯一的区别就是java虚拟机栈是描述Java方法的,而本地方法栈是描述Native方法的。

5.Java堆

正常来说,java堆内存是虚拟机所管理的内存中最大的一块区域。这块区域是被所有线程共享的内存空间。这块区域也就是我的java线程文章中关于volatile中所讲的主内存区域。

这一块区域的主要作用就是存放对象实例。在javaweb中不管是new的对象实例,还是通过其它方法创建的实例,几乎都存放在这里。

这一块区域也是垃圾收集器管理的主要区域。因此很多时候垃圾收集器也叫做“GC堆”。关于如何回收对象实例,会在后面的章节详细讲述。

当没有内存再分配对象实例时,会报"内存溢出异常(OutofMemoryError)"。

6.方法区

这一块区域也是被所有线程所共享的内存空间。

它主要存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。其中常量与静态变量也就是我们在代码中用static和final修饰的变量。

垃圾收集器对这一块也有回收,只不过回收行为在这一块区域比较少。主要回收目标是对常量池的回收以及对类型的卸载。

当无法满足内存分配要求时,会报"内存溢出异常(OutofMemoryError)"。

其中方法区内有一部份叫“运行时常量池”,我们再来描述一下这个运行时常量池。

运行时常量池

class文件中存储了类的版本、字段、方法、接口等描述信息外,还存储了编译期常量池的各种字面量和符号引用,也就是我前面说的static和final修饰的变量,这些变量将在类加载后存入运行时常量池。

还有一些运行期间产生的新的常量也会存入运行时常量池中,比如String类的intern()方法。

常量池属于方法区的一部份,所以也有"内存溢出异常(OutofMemoryError)"的风险。

7.直接内存

这个内存空间不属于虚拟机管理的内存,但它确实也会被使用。

比如:NIO(也许以后有空了会写关于这一方面的文章),它引入了通道(Channel)与缓冲区(Buffer)的I/O方式,它可以使用Native函数库直接分配出堆外内存(这块内存就是直接内存),然后通过一个存储在java堆(前面所描述的java堆)中的DirectByteByffer对象作为这块内存的引用进行操作,这样避免了java堆和native堆中来回复制数据,提高了一些性能。

我们在配置虚拟机参数时,会根据实际的内存设置-Xmx等参数,但往往会忽略了这块内存,这样很容易会造成"内存溢出异常(OutofMemoryError)"的风险。比如:服务器的实际内存为4G,我们设置了-Xmx的内存为4G,但是当分配直接内存时,就会发现没有多余的内存可分配了,就会报“内存溢出异常(OutofMemoryError)”。

猜你喜欢

转载自blog.csdn.net/wangzx19851228/article/details/81134449