JVM执行Java程序的过程中,会使用到各种数据区域,这些区域有各自的用途、创建和销毁时间。根据《Java虚拟机规范》,JVM包括下列几个运行时数据区域,如下图所示:

其中红色部分是线程私有的,即每个线程各自都有自己的一份。绿色部分是各个线程共享的。

1.PC寄存器(The pc Register)

(1)每一个Java线程都有一个PC寄存器。

(2)PC寄存器是用于存储每个线程下一步将执行的JVM指令,如该方法为native的,则PC寄存器中不存储任何信息。

(3)此内存区域是唯一一个在JVM Spec中没有规定任何OutOfMemoryError情况的区域。

2.JVM栈(Java Virtual Machine Stacks)

(1)JVM栈是线程私有的,每个线程创建的同时都会创建JVM栈,与程PC寄存器一样,JVM栈的生命周期也是与线程相同。

(2)JVM栈中存放的为当前线程中局部基本类型的变量(Java中定义的八种基本类型:boolean、char、byte、short、int、long、float、double)、部分的返回结果以及Stack Frame,非基本类型的对象在JVM栈上仅存放一个指向堆上的地址。

(3)在JVM Spec中对这个区域规定了两种异常状况:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果JVM栈可以动态扩展(JVM Spec中允许固定长度的JVM栈),当扩展时无法申请到足够内存则抛出OutOfMemoryError异常。

(4)由于JVM栈是线程私有的,因此其在内存分配上非常高效,并且当线程运行完毕后,这些内存也就被自动回收。

3.本地方法栈(Native Method Stacks)

(1)本地方法栈与JVM栈所发挥作用是类似的,只不过JVM栈为虚拟机运行JVM原语服务,而本地方法栈是为虚拟机使用到的Native方法服务。它的实现的语言、方式与结构并没有强制规定,甚至有的虚拟机(譬如Sun Hotspot虚拟机)直接就把本地方法栈和JVM栈合二为一。

(2)和JVM栈一样,这个区域也会抛出StackOverflowError和OutOfMemoryError异常。

4.方法区(Method Area)

(1)别名叫做Non-Heap(非堆)。

(2)方法区域存放了所加载的类的信息(名称、修饰符等)、类中的静态变量、类中定义为final类型的常量、类中的Field信息、类中的方法信息,当开发人员在程序中通过Class对象中的getName、isInterface等方法来获取信息时,这些数据都来源于方法区域。

(3)方法区域是全局共享的,在一定的条件下它也会被GC,当方法区域需要使用的内存超过其允许的大小时,会抛出OutOfMemory的错误信息。

(4)在Sun JDK中这块区域对应的为Permanet Generation,又称为永久代,默认为64M,可通过-XX:PermSize以及-XX:MaxPermSize来指定其大小。

5.运行时常量池(Runtime Constant Pool)

(1)类似C中的符号表,存放的为类中的固定的常量信息、方法和Field的引用信息等,其空间从方法区域中分配。

(2)Class文件中除了有类的版本、字段、方法、接口等描述等信息外,还有一项信息是常量表(constant_pool table),用于存放编译期已可知的常量,这部分内容将在类加载后进入方法区(永久代)存放。但是Java语言并不要求常量一定只有编译期预置入Class的常量表的内容才能进入方法区常量池,运行期间也可将新内容放入常量池(最典型的String.intern()方法)。

(3)运行时常量池是方法区的一部分,自然受到方法区内存的限制,当常量池无法在申请到内存时会抛出OutOfMemoryError异常。

6.Java堆(Java Heap)

Java堆是被所有线程共享的,在虚拟机启动时创建。它是JVM用来存储对象实例以及数组值的区域,绝大部分的对象实例都在这里分配。在逃逸分析和标量替换优化技术出现后,并不是所有的对象实例都是在这里分配,但我们可以粗略地认为Java中所有通过new创建的对象的内存都在此分配。Heap中的对象的内存需要等待GC进行回收。

大小通过-Xms和-Xmx来控制,-Xms为JVM启动时申请的最小Heap内存(默认为物理内存的1/64但小于1G),-Xmx为JVM可申请的最大Heap内存(默认为物理内存的1/4)。默认当空余堆内存小于40%时,JVM会增大Heap的大小到-Xmx指定的大小,可通过-XX:MinHeapFreeRatio=来指定这个比例。 默认当空余堆内存大于70%时,JVM会将Heap的大小往-Xms指定的大小调整,可通过-XX:MaxHeapFreeRatio=来指定这个比例。但对于运行系统而言,为了避免频繁的Heap Size的调整,通常都会将-Xms和-Xmx的值设成一样,因此这两个用于调整比例的参数通常是没用的。

JVM将Heap分为New Generation和Old Generation(或Tenured Generation)两块来进行管理:

(1)New Generation

又称为新生代,程序中新建的对象都将分配到新生代中,新生代又由Eden Space和两块Survivor Space构成,可通过-Xmn参数来指定其大小。发生在新生代的垃圾收集动作称为Minor GC。

(2)Old Generation

又称为旧生代(老年代),用于存放程序中经过几次垃圾回收还存活的对象,例如缓存的对象等,旧生代所占用的内存大小即为-Xmx指定的大小减去-Xmn指定的大小。发生在老年代的垃圾收集动作成为Major GC/Full GC。

(3)内存分配策略

a. 对象优先在Eden分配。b. 大对象直接进入老年代。c. 长期存活的对象将进入老年代。

对堆的解释:

1)堆是JVM中所有线程共享的,因此在其上进行对象内存的分配均需要进行加锁,这也导致了new对象的开销是比较大的。

2)鉴于上面的原因,Sun Hotspot JVM为了提升对象内存分配的效率,对于所创建的线程都会分配一块独立的空间,这块空间又称为TLAB(Thread Local Allocation Buffer),其大小由JVM根据运行的情况计算而得,在TLAB上分配对象时不需要加锁,因此JVM在给线程的对象分配内存时会尽量的在TLAB上分配,在这种情况下JVM中分配对象内存的性能和C基本是一样高效的,但如果对象过大的话则仍然是直接使用堆空间分配。

3)TLAB仅作用于新生代的Eden Space,因此在编写Java程序时,通常多个小的对象比大的对象分配起来更加高效,但这种方法同时也带来了两个问题,一是空间的浪费,二是对象内存的回收上仍然没法做到像Stack那么高效,同时也会增加回收时的资源的消耗,可通过在启动参数上增加-XX:+PrintTLAB来查看TLAB这块的使用情况。

参考资料

《深入java虚拟机:VM高级特性与最佳实践》

JVM内存管理:深入Java内存区域与OOM http://icyfenix.iteye.com/blog/802573

http://itindex.net/detail/48698-jvm-%E5%86%85%E5%AD%98

深入理解JVM—JVM内存模型  http://yhjhappy234.blog.163.com/blog/static/316328322011101723933875/?suggestedreading&wumii

《The Java® Virtual Machine Specification》 http://docs.oracle.com/javase/specs/jvms/se8/html/index.html

JVM学习笔记:Java运行时数据区域的更多相关文章

  1. Jvm基础(1)-Java运行时数据区

    最近在看<深入理解Java虚拟机>,里面讲到了Java运行时数据区,这是Jvm基本知识,把读书笔记记录在此.这些知识属于常识,都能查到的,如果我有理解不对的地方,还请指出. 首先把图贴上来 ...

  2. Java运行时数据区域分析

    Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则依赖用户线程的启动和结 ...

  3. JVM发展史和Java运行时内存区域

    目前三大主流JVM: Sun HotSpot:Sun于1997年收购Longview Technologies公司所得.Sun于2009年被Oracle收购. BEA JRockit:BEA于2002 ...

  4. Java运行时数据区域划分

    Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以及创建和销毁时间.根据<Java虚拟机规范(Java SE 7版>的规定,J ...

  5. (二)、JAVA运行时数据区域

    根据<Java 虚拟机规范(Java SE 7版)>规定,Java虚拟机所管理的内存,将会包括以下几个运行时数据区域: 注: 1.由所有线程共享的数据区: 对应 java内存模型的主内存, ...

  6. JVM学习笔记一:Java运行时数据区域

    1. 程序计数器 当前线程所执行的字节码的行号指示器. 2. Java虚拟机栈 线程私有,与线程具有相同生命周期.用于存储局部变量表.操作数栈.动态链表.方法出口等信息. 局部变量表存放内容: 基本数 ...

  7. 深入理解JVM虚拟机:(一)Java运行时数据区域

    概述 JVM是Java语言的精髓所在,因为它Java语言实现了跨平台运行,以及自动内存管理机制等,本文将从概念上介绍JVM内存的各个区域,说明个区域的作用. JVM运行时数据区模型 Java虚拟机在执 ...

  8. java运行时数据区域

    数据区域有:程序计步器,虚拟机栈,本地方法栈,java堆,方法区 程序计步器: 它是一块较小的内存空间,它的作用可以看做是当先线程所执行的字节码的信号指示器. 每一条JVM线程都有自己的PC寄存器,各 ...

  9. [JVM-1]Java运行时数据区域

    Java虚拟机(JVM)内部定义了程序在运行时需要使用到的内存区域 这些区域都有自己的用途,以及创建和销毁的时间.有些区域随着虚拟机进程的启动而存在,有的区域则依赖用户线程的启动和结束而销毁和建立. ...

随机推荐

  1. PHP & Delphi 語法

    明 C(区分大小写) Delphi(不区分大小写) PHP(区分大小写) 整型变量的定义 1 2 3 4 5 6 7 char a = 'a';         /* 8位有符号*/ int a=10 ...

  2. 李学斌:论复杂系统中的应用间协作V3

    说明 本文主要讨论了巨型复杂业务系统的一种构建思路,力图实现决策意志的快速.准确.一致的下传并简化实施成本提供实施效率.通过全业务领域的即时流程编排,实现全网业务IT系统的快速建设与迭代.本文所讲的方 ...

  3. codevs http://www.codevs.cn/problem/?problemset_id=1 循环、递归、stl复习题

    12.10高一练习题 1.要求: 这周回顾复习的内容是循环.递归.stl. 不要因为题目简单就放弃不做,现在就是练习基础. 2.练习题: (1)循环   题目解析与代码见随笔分类  NOI题库 htt ...

  4. jboss eap 6.2+ 版本中 加密datasource密码等敏感信息

    默认情况下,在jboss eap 6.2+ 管理控制台创建datasource后,会在standalone.xml(独立模式)或host.xml(域模式)中以明文保存相关敏感信息. 这会给服务器留下安 ...

  5. 对react的几点质疑

    现在react.js如火如荼,非常火爆,昨天抽了一天来看了下这项技术.可能就看了一天,研究的不深入,但是我在看的过程中发现来了很多疑惑,这里拿出来和那家分享讨论以此共勉. 在我接触的前端以后,让我感觉 ...

  6. spring boot 自动部署方案

    现在主流的自动部署方案大都是基于Docker的了,但传统的自动部署方案比较适合中小型公司,下面的方案就是比较传统的自动部署方案. 1.为什么需要自动部署 基于微服务的架构,自动部署显得非常重要.因为每 ...

  7. Java语法笔记

    目录 知识点 不支持 恶心事 与C#的区别 组件 学习资料 母版页 知识点 类 静态方法,即可以在类上被调用,也可以在实例对象上被调用. Java类 先执行静态构造函数,再执行静态方法或静态字段,所以 ...

  8. C#版的MapReduce

    如果不知道MapReduce是怎么工作的,请看这里,如果不知道MapReduce是什么,请google之! 今天“闲”来无事,忽想起C#里没有MapReduce的方法,构思之,coding之: #re ...

  9. 将Microsoft Ajax Minifier集成到VS2013对JS、CSS进行编译时压缩

    在网站发布中,一般要将js,css文件压缩减少体积,以减少在HTTP请求中的流量.将Microsoft Ajax Minifier集成到VS2013中就可以对JS.CSS进行编译时压缩. VS2013 ...

  10. keypress,keydown,keyup,charCode,keyCode兼容性问题

    keypress对应的是字符编码,如“ABC”,“123”之类,有大小写之分(有兼容性问题) keydown,keyup对应的是键盘的键码,无大小写之分,每个键盘都有一个键码(无兼容性问题) 使用ke ...