内存的动态分配和垃圾回收技术对于Java与C++技术人员来说,就像一座围城,内部的人想出来,外部的人想进去。对于Java程序员来说,JVM的自动内存管理机制为他们解决了很多的问题和繁琐的工作。但一旦出现内存泄露或溢出方面的问题,如果不了解JVM的内存,那么解决这些问题将是一件异常艰难的工作。
JVM在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。如下图所示:
一:程序计数器
程序计数器是一块较小的内存空间,它可以看做是当前线程所执行的字节码行号的执行器。JVM的多线程是通过时间片轮流切换的方式来实现的,某个时刻,一个CPU都只执行一条线程中的指令。因此,为了线程切换后恢复到正确的执行位置,每个线程都有一个独立的程序计数器。此内存区域没有大小限制,是唯一一个没有确定OutOfMemoryErrom情况的区域。
二:Java虚拟机栈
Java虚拟机栈也是线程私有的,它的生命周期同线程同步。Java执行方法时都会创建一个栈帧(Stack Frame)用于存储局部变量表,操作数栈,动态链接和方法出口等信息。
如果线程请求的栈深度大于JVM所允许的深度,将抛出StackOverflowError异常;如果虚拟机栈可以动态扩展,但扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常。
三:本地方法栈
本地方法栈与JVM栈所发挥的作用非常相似。区别仅在于本地方法栈是为JVM使用到的Native方法服务。
四:Java 堆
Java堆是被所有线程共享的一块内存区域,是JVM所管理的内存中最大的一块,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有对象的实例都在这里分配内存。
Java堆是垃圾收集器管理的主要区域。
Java堆的分配可以通过参数 -Xmx和-Xms来控制。
五:方法区
方法区也是各个线程共享的内存区域。它用于存储已被JVM加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。
运行时常量池:是方法区的一部分。class文件中除了有类的版本,字段,方法,接口等描述信息外;还有一项常量池,用于存放编译期生成的各种字面量和符号引用。
JVM遇到一条new指令时,首先将会去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载,解析和初始化。如果没有就必须先执行相应的类加载过程。
六:内存参数设置
-Xms512M Java堆最小512M
-Xmx512M Java堆最大512M
-Xss128K Java虚拟机栈+本地方法栈的大小为128K
-XX:PermSize=64M 方法区最小64M
-XX:MaxPermSize=64M 方法区最大64M

1.jpg