java虚拟机

java虚拟机

JVM specification对JVM内存的描述

首先我们来了解JVM specification中的JVM整体架构。如下图:

 


    
主要包括两个子系统和两个组件: Class loader( 类装载器 ) 子系统, Execution engine( 执行引擎 ) 子系统; Runtime data area ( 运行时数据区域 ) 组件, Native interface( 本地接口 ) 组件。
     Class loader
子系统的作用 :根据给定的全限定名类名 ( java.lang.Object) 来装载 class 文件的内容到 Runtime data area 中的 method area( 方法区域 ) Javsa 程序员可以 extends java.lang.ClassLoader 类来写自己的 Class loader
      Execution engine
子系统的作用 :执行 classes 中的指令。任何 JVM specification 实现 (JDK) 的核心是 Execution engine 换句话说: Sun JDK IBM JDK 好坏主要取决于他们各自实现的 Execution  engine 的好坏。每个运行中的线程都有一个 Execution engine 的实例。
     Native interface
组件 :与 native libraries 交互,是其它编程语言交互的接口。  
     Runtime data area
组件:这个组件就是 JVM 中的内存

  • 运行时数据组件的详解介绍:
    

Runtime data area 主要包括五个部分:Heap (堆), Method Area(方法区域), Java Stack(java的栈), Program Counter(程序计数器), Native method stack(本地方法栈)。Heap 和Method Area是被所有线程的共享使用的;而Java stack, Program counter 和Native method stack是以线程为粒度的,每个线程独自拥有。

Heap
Java程序在运行时创建的所有类实或数组都放在同一个堆中。
而一个Java虚拟实例中只存在一个堆空间,因此所有线程都将共享这个堆。每一个java程序独占一个JVM实例,因而每个java程序都有它自己的堆空间,它们不会彼此干扰。但是同一java程序的多个线程都共享着同一个堆空间,就得考虑多线程访问对象(堆数据)的同步问题。 (这里可能出现的异常java.lang.OutOfMemoryError: Java heap space)

JVM堆一般又可以分为以下三部分:

Ø Perm

Perm代主要保存class,method,filed对象,这部门的空间一般不会溢出,除非一次性加载了很多的类,不过在涉及到热部署的应用服务器的时候,有时候会遇到java.lang.OutOfMemoryError : PermGen space 的错误,造成这个错误的很大原因就有可能是每次都重新部署,但是重新部署后,类的class没有被卸载掉,这样就造成了大量的class对象保存在了perm中,这种情况下,一般重新启动应用服务器可以解决问题。

Ø Tenured

Tenured区主要保存生命周期长的对象,一般是一些老的对象,当一些对象在Young复制转移一定的次数以后,对象就会被转移到Tenured区,一般如果系统中用了application级别的缓存,缓存中的对象往往会被转移到这一区间。

Ø Young

Young区被划分为三部分,Eden区和两个大小严格相同的Survivor区,其中Survivor区间中,某一时刻只有其中一个是被使用的,另外一个留做垃圾收集时复制对象用,在Young区间变满的时候,minor GC就会将存活的对象移到空闲的Survivor区间中,根据JVM的策略,在经过几次垃圾收集后,任然存活于Survivor的对象将被移动到Tenured区间。


Method area
在Java虚拟机中,被装载的class的信息存储在Method area的内存中。
当虚拟机装载某个类型时,它使用类装载器定位相应的 class文件,然后读入这个class文件内容并把它传输到虚拟机中。紧接着虚拟机提取其中的类型信息,并将这些信息存储到方法区。该类型中的类(静态)变量同样也存储在方法区中。与Heap 一样,method area是多线程共享的,因此要考虑多线程访问的同步问题。比如,假设同时两个线程都企图访问一个名为Lava的类,而这个类还没有内装载入虚拟机,那么,这时应该只有一个线程去装载它,而另一个线程则只能等待。 (这里可能出现的异常java.lang.OutOfMemoryError: PermGen full)

Java stack
       Java stack以帧为单位保存线程的运行状态。虚拟机只会直接对Java stack执行两种操作:以帧为单位的压栈或出栈。
每当线程调用一个方法的时候,就对当前状态作为一个帧保存到 java stack中(压栈);当一个方法调用返回时,从java stack弹出一个帧(出栈)。栈的大小是有一定的限制,这个可能出现StackOverFlow问题。 下面的程序可以说明这个问题。

 

public class TestStackOverFlow {
 
     public static void main(String[] args) {
 
            Recursive r = new Recursive();
            r.doit(10000);
            // Exception in thread "main" java.lang.StackOverflowError
     }
 
}
 
class Recursive {
 
     public int doit(int t) {
            if (t <= 1) {
                    return 1;
            }
            return t + doit(t - 1);
     }
 
}

 

Program counter
每个运行中的Java程序,每一个线程都有它自己的PC寄存器,也是该线程启动时创建的。PC寄存器的内容总是指向下一条将被执行指令的饿&ldquo;地址&rdquo;,这里的&ldquo;地址&rdquo;可以是一个本地指针,也可以是在方法区中相对应于该方法起始指令的偏移量。

Native method stack
对于一个运行中的Java程序而言,它还能会用到一些跟本地方法相关的数据区。当某个线程调用一个本地方法时,它就进入了一个全新的并且不再受虚拟机限制的世界。本地方法可以通过本地方法接口来访问虚拟机的运行时数据区,不止与此,它还可以做任何它想做的事情。比如,可以调用寄存器,或在操作系统中分配内存等。总之,本地方法具有和JVM相同的能力和权限。 (这里出现JVM无法控制的内存溢出问题native heap OutOfMemory )

JVM提供了相应的参数来对内存大小进行配置。



正如上面描述,JVM中堆被分为了3个大的区间,同时JVM也提供了一些选项对Young,Tenured的大小进行控制。

Ø Total Heap 

-Xms :指定了JVM初始启动以后初始化内存

-Xmx:指定JVM堆得最大内存,在JVM启动以后,会分配-Xmx参数指定大小的内存给JVM,但是不一定全部使用,JVM会根据-Xms参数来调节真正用于JVM的内存

-Xmx -Xms之差就是三个Virtual空间的大小

Ø Young Generation

-XX:NewRatio=8意味着tenured  young的比值81,这样eden+2*survivor=1/9

堆内存

-XX:SurvivorRatio=32意味着eden和一个survivor的比值是321,这样一个Survivor就占Young区的1/34.

-Xmn 参数设置了年轻代的大小

Ø Perm Generation

-XX:PermSize=16M -XX:MaxPermSize=64M

Thread Stack

-XX:Xss=128K

 


你可能感兴趣的:(java虚拟机)