首页 > 技术 > jvm学习--内存模型

jvm学习--内存模型

2012年2月21日 发表评论 阅读评论

JVM是Java Virtual Machine(Java虚拟机)的缩写,Java语言使用模式Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java 虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。


 

JVM体系结构

先介绍一下JVM的体系结构,它由类加载器子系统,运行时数据区,执行引擎以及本地方法接口组成:

1. 类加载器子系统 主要用于定位类定义的二进制信息,然后将这些信息解析并加载至虚拟机,转化为虚拟机内部的类型信息的数据结构。类加载器子系统还承担着安全性的责任,并且是JVM的动态链接和动态加载的基础。每一个被加载的class文件需要经过四次校验才能被加载。
2. 运行时数据区 是JVM运行时的内存空间的组织,逻辑上又划分为多个区,这些区的生命周期和它是否线程共享有关,它们分别是:
        :一个JVM只有一个堆,所有线程共享;存放所有类实例和数组; 
       方法区:一个JVM只有一个方法区,所有线程共享;方法区大小不固定,可以被调整;存放类型信息和运行时常量池(Runtime Constant Pool);方法区也可以被GC;
       PC(Program Counter):JVM会为每一个创建的线程分配一个PC寄存器;大小为一个字节;内容是下一条将执行指令的地址;PC是JVM规范中唯一没有规定会抛出异常的存储区。
        JVM栈:线程启动时,JVM会为其分配一个JVM栈;JVM对栈只有“压栈”,“出栈”的操作,操作的单位是栈帧;栈帧由三部分组成“局部变量区”,“操作数栈“,“栈帧数据区”
JVM规范规定栈可以抛出两种异常:(1)StackOverflowException,在栈的深度大于某个规定值的情况下抛出。(2)OutOfMemoryException,在为新栈帧分配内存或者是为线程分配栈的内存时,申请不到足够的内存的情况下抛出。
        本地方法栈:用于支持本地方法调用,抛出的异常与JVM栈相同。
3. 执行引擎 用于执行JVM字节码指令,主要由两种实现方式:(1)将输入的字节码指令在加载时或执行时翻译成另外一种虚拟机指令;(2)将输入的字节码指令在加载时或执行时翻译成宿主主机本地CPU的指令集。这两种方式对应着字节码的解释执行和即时编译。

JVM内存结构 

 1 JVM Process Heap
2 Java Object Heap(JAVA Heap)
通常被称为JVM  heap ,容易和JVM process Heap混淆,它是用来存储java OBject的如:Object的实例和Object的基本数据及引用。 
-XX:MinHeapFreeRatio=Default is 40 (40%)
-XX:MaxHeapFreeRatio=Default 70% J
VM初始分配的内存由-Xms指定,默认是物理内存的1/64;JVM最大分配的内存由-Xmx指定,默认是物理内存的1/4。默认空余堆内存小 于40%时,JVM就会增大堆直到-Xmx的最大限制;空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制。因此服务器一般设置-Xms、-Xmx相等以避免在每次GC后调整堆的大小。
  3、Young Generation
所有新创建的Object 都将会存储在这里。
配置方式 :-Xmn – not preferred (fixed value)-XX:NewRatio=<value> - preferred(dynamic)官方推荐的配置是新生代(Young Generation)占整个Java Object Heap内存的33%
4、Eden Space
新的Object总是创建在Eden Space。 
5、Old Generation 
如果Young Generation的数据在一次或多次GC后存活下来,那么将被转移到OldGeneration。 
6、Survivor Spaces 
GC时,Eden中活的对象复制到surivivor spaces ,当对象达到最打值(老化)时,被送到Old Generation10、Tenured Space5MB min 44MB max (default) 这就是传说中的老年代,官方给的解释就是:pool containing objects that have existed for some time in the survivor space.
  11、Everything else
这其实就是我们常常见到的no-heap  
12、Permanent Space
4MB initial , 63MB max存储class的函数及其他的meta Data.
配置方式:-XX:PermSize=<value> (initial)-XX:MaxPermSize=<value> (max) 
13、Code Generation 
转换byte code 为native code.基本不会导致内存异常。如果该操作没有足够的空间,JVM可能会导致崩溃。 
 14、Socket Buffers
包括两部分:1:Receive buffer ~37k   2:Send buffer ~25k需要在JAVA代码中来控制他,所以在外部无法配置。 他可能导致的异常:IOException: Too many open files (forexample)  
15、Threaded JVM Stacks 
Thread Stacks:表示各个Thread所分配的空间。默认至取决于OS/JVM线程数增加,Thread Stacks则增大。
配置: –Xss 异常:java.lang.OutOfMemoryError:unable to create new native thread如果-Xss配置的太小,会引起java.lang.StackOverflowError 
16、Direct Memory Space
 他可以让开发人员映射内存到java Object Heap外。配置: XX:MaxDirectMemorySize=<value>  
17、JNI Code 
 JNI code本身使用的内存非常小。
 19、JNI allocate memory
JNI 程序本身也需要分配内存。
  18、Garbage Collection 
其实GC也是需要内存的,gc线程的消耗以及存放GC所缓存的信

常见异常及解决方法 

 java.lang.OutOfMemoryError: Java heap space

原因:Heap内存溢出,意味着Young和Old generation的内存不够。

解决:调整java启动参数-Xms -Xmx 来增加Heap内存。

java.lang.OutOfMemoryError: unable to create new native thread

原因:Stack空间不足以创建额外的线程,要么是创建的线程过多,要么是Stack空间确实小了。

解决:由于JVM没有提供参数设置总的stack空间大小,但可以设置单个线程栈的大小;而系统的用户空间一共是3G,除了Text/Data/BSS /MemoryMapping几个段之外,Heap和Stack空间的总量有限,是此消彼长的。因此遇到这个错误,可以通过两个途径解决:1.通过-Xss启动参数减少单个线程栈大小,这样便能开更多线程(当然不能太小,太小会出现StackOverflowError);2.通过-Xms -Xmx 两参数减少Heap大小,将内存让给Stack(前提是保证Heap空间够用)。

java.lang.OutOfMemoryError: PermGen space

原因:Permanent Generation空间不足,不能加载额外的类。

解决:调整-XX:PermSize= -XX:MaxPermSize= 两个参数来增大PermGen内存。一般情况下,这两个参数不要手动设置,只要设置-Xmx足够大即可,JVM会自行选择合适的PermGen大小。

java.lang.OutOfMemoryError: Requested array size exceeds VM limit

原因:这个错误比较少见(试着new一个长度1亿的数组看看),同样是由于Heap空间不足。如果需要new一个如此之大的数组,程序逻辑多半是不合理的。

解决:修改程序逻辑吧。或者也可以通过-Xmx来增大堆内存。

在GC花费了大量时间,却仅回收了少量内存时,也会报出OutOfMemoryError ,我只遇到过一两次。当使用-XX:+UseParallelGC或-XX:+UseConcMarkSweepGC收集器时,在上述情况下会报错,在HotSpot GC Turning文档 上有说明:

The parallel(concurrent) collector will throw an OutOfMemoryError if too much time is being spent in garbage collection: if more than 98% of the total time is spent in garbage collection and less than 2% of the heap is recovered, an OutOfMemoryError will be thrown.

对这个问题,一是需要进行GC turning,二是需要优化程序逻辑。

java.lang.StackOverflowError

原因:这也内存溢出错误的一种,即线程栈的溢出,要么是方法调用层次过多(比如存在无限递归调用),要么是线程栈太小。

解决:优化程序设计,减少方法调用层次;调整-Xss参数增加线程栈大小。

 IOException: Too many open files

原因: 这个是由于TCP connections 的buffer 大小不够用了。

 java.lang.OutOfMemoryError:Direct buffer memory

 解决:调整-XX:MaxDirectMemorySize=<value>

 
 

 

分类: 技术 标签:
  1. 本文目前尚无任何评论.
  1. 本文目前尚无任何 trackbacks 和 pingbacks.