上一篇主要描述了JVM的一些基本概念,和大致的结构。这一篇我们详细学习非堆区域(除了heap内容之外的全称为栈不知道是否合适,因此干脆叫非堆)的内容。在后一篇里面我们再学习堆的内容,包括GC策略等。下图列出了JVM规范中JVM的整个架构。
从图中可以看出,JVM内存主要由class load subsystem、runtime data areas、execution engine组成。除了heap使用-Xmx指定内存,其他的都占用java进程内存寻址空间减去heap内存,在内存充足的情况下。 其中class load subsystem和execution engine对应用比较透明,就不在这里讨论了。我们重点讨论runtime data areas。
首先看method area,参考下图,method area是存放class的定义的,heap存放class实例化的object(特殊:class本身的表达对象放在方法区),这两个区域都是被整个JVM共享使用的。
方法区主要包括以下内容:
- Methods of a class (including the bytecodes)
- Names of the classes (in the form of an object that points to a string also in the permanent generation)
- Constant pool information (data read from the class file, see chapter 4 of the JVM specification for all the details).
- Object arrays and type arrays associated with a class (e.g., an object array containing references to methods).
- Internal objects created by the JVM (java/lang/Object or java/lang/exception for instance)
- Information used for optimization by the compilers (JITs)
参考下图,Object和Class的关系,还有Class的表达对象kclassKclass。
方法区在SUN的jdk中又叫持久代(Perm Gen),可以指定大小,一旦不满足则出现java.lang.OutOfMemoryError: PermGen space。在IBMD的jdk中不能设置大小,在0~(Java进程的寻址空间大小-heap大小)之间动态扩展(操作系统内存足够的情况下)。
java stacks存放线程私有的数据,如局部变量和线程变量。他的结构如下图所示:
当创建一个线程的时候分配线程自身的pc register和Java stack,Java stack由一些stack frames组成,每个stack frame包含了Java方法调用的状态。当线程调用java方法的时候,JVM将一个新的frame压入Java stack,当方法调用结束,弹出这个frame并丢弃。JVM本身没有地方保持中间变量的值。指令集用Java stack 存储中间变量的值。Java stack大小不够的话,会出现如下错误:java.lang.OutOfMemoryError: unable to create new native thread
native method stacks里面包括Socket Buffers、Direct Memory Space、JNI Code、JNI Allocated Memory。