内存作为系统中重要的资源,对于系统稳定运行和高效运行起到了关键的作用,Java和C之类的语言不同,不需要开发人员来分配内存和回收内存,而是由JVM来管理对象内存的分配以及对象内存的回收(又称为垃圾回收、GC),这对于开发人员来说确实大大降低了编写程序的难度,但带来的一个副作用就是,当系统运行过程中出现JVM抛出的内存异常(例如OutOfMemoryError)的时候,很难知道原因是什么,另外一方面,要编写高性能的程序,通常需要借助内存来提升性能,因此如何才能合理的使用内存以及让JVM合理的进行内存的回收是必须掌握的,本文将主

AD:2013云计算架构师峰会课程资料下载

其实对于我们一般理解的计算机内存,它算是CPU与计算机打交道最频繁的区域,所有数据都是先经过硬盘至内存,然后由CPU再从内存中获取数据进行处理,又将数据保存到内存,通过分页或分片技术将内存中的数据再flush至硬盘。那JVM的内存结构到底是如何呢?JVM做为一个运行在操作系统上,但又独立于os运行的平台,它的内存至少应该包括象寄存器、堆栈等区域。

JVM在运行时将数据划分为了6个区域来存储,而不仅仅是大家熟知的Heap区域,这6个区域图示如下:

JVM内存的分配结构示意图

下面将逐一介绍下各个区域所做的工作及其充当的功能。

PC Register(PC寄存器)

PC寄存器是一块很小的内存区域,主要作用是记录当前线程所执行的字节码的行号。字节码解释器工作时就是通过改变当前线程的程序计数器选取下一条字节码指令来工作的。任何分支,循环,方法调用,判断,异常处理,线程等待以及恢复线程,递归等等都是通过这个计数器来完成的。

由于Java多线程是通过交替线程轮流切换并分配处理器时间的方式来实现的,在任何一个确定的时间里,在处理器的一个内核只会执行一条线程中的指令。因此为了线程等待结束需要恢复到正确的位置执行,每条线程都会有一个独立的程序计数器来记录当前指令的行号。计数器之间相互独立互不影响,我们称这块内存为“线程私有”的内存。

如果所调用的方法为native的,则PC寄存器中不存储任何信息。

l  JVM栈

JVM栈是线程私有的,每个线程创建的同时都会创建JVM栈,JVM栈中存放的为当前线程中局部基本类型的变量(java中定义的八种基本类型:boolean、char、byte、short、int、long、float、double)、部分的返回结果以及Stack Frame,非基本类型的对象在JVM栈上仅存放一个指向堆上的地址,因此Java中基本类型的变量是值传递,而非基本类型的变量是引用传递,Sun           JDK的实现中JVM栈的空间是在物理内存上分配的,而不是从堆上分配。

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

当JVM栈的空间不足时,会抛出StackOverflowError的错误,在Sun JDK中可以通过-Xss来指定栈的大小,例如如下代码:


  1. new Thread(new Runnable(){
  2. public void run() {
  3. loop(0);
  4. }
  5. private void loop (int i){
  6. if(i!=1000){
  7. i++;
  8. loop (i);
  9. }
  10. else{
  11. return;
  12. }
  13. }
  14. }).start();

当JVM参数设置为-Xss1K,运行后会报出类似下面的错误:

Exception in thread "Thread-0"java.lang.StackOverflowError

l  堆(Heap)

Heap是大家最为熟悉的区域,它是JVM用来存储对象实例以及数组值的区域,可以认为Java中所有通过new创建的对象的内存都在此分配,Heap中的对象的内存需要等待GC进行回收,Heap在32位的操作系统上最大为2G,在64位的操作系统上则没有限制,其大小通过-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中对于堆内存的分配、使用、管理、收集等有更为精巧的设计,具体可以在JVM堆内存分析中进行详细介绍。

当堆中需要使用的内存超过其允许的大小时,会抛出OutOfMemory的错误信息。

l  方法区域(MethodArea)

方法区域存放了所加载的类的信息(名称、修饰符等)、类中的静态变量、类中定义为final类型的常量、类中的Field信息、类中的方法信息,当开发人员在程序中通过Class对象中的getName、isInterface等方法来获取信息时,这些数据都来源于方法区域,可见方法区域的重要性。同样,方法区域也是全局共享的,它在虚拟机启动时在一定的条件下它也会被GC,当方法区域需要使用的内存超过其允许的大小时,会抛出OutOfMemory的错误信息。

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

l  运行时常量池(RuntimeConstant Pool)

类似C中的符号表,存放的为类中的固定的常量信息、方法和Field的引用信息等,其空间从方法区域中分配。类或接口的常量池在该类的class文件被java虚拟机成功装载时分配。

l  本地方法堆栈(NativeMethod Stacks)

JVM采用本地方法堆栈来支持native方法的执行,此区域用于存储每个native方法调用的状态。

例如有这么一段代码:


  1. public class A {
  2. public static void main(String[]args){
  3. String a="a";
  4. String b="b";
  5. String ab="ab";
  6. System.out.println((a+b)==ab);       // false
  7. System.out.println(("a"+"b")==ab);   // true
  8. final String afinal="a";
  9. String result=afinal+"b";
  10. System.out.println(result==ab);      // true
  11. String plus=a+"b";
  12. System.out.println(plus==ab);        // false
  13. System.out.println(plus.intern()==ab);  // true
  14. }
  15. }

分析下上面代码执行的结果,可通过javap –verbose A来辅助理解分析。

l  (a+b)==ab

a+b是两个变量相加,需要到运行时才能确定其值,到运行时后JVM会为两者相加后产生一个新的对象,因此a+b==ab的结果为false。

l  (“a”+”b”)==ab

“a”+”b”是常量,在编译时JVM已经将其变为”ab”字符串了,而ab=”ab”也是常量,这两者在常量池即为同一地址,因此(“a”+”b”)==ab为true。

l  result==ab

result=afinal+”b”,afinal是个final的变量, result在编译时也已经被转变为了”ab”,和”ab”在常量池中同样为同一地址,因此result==ab为true。

l  plus=ab

plus和a+b的情况是相同的,因此plus==ab为false。

l  plus.intern()==ab

这里的不同点在于调用了plus.intern()方法,这个方法的作用是获取plus指向的常量池地址,因此plus.intern()==ab为true。

在掌握了JVM对象内存分配的机制后,接下来看看JVM是如何做到自动的对象内存回收的,这里指的的是Heap以及Method Area的回收,其他几个区域的回收都由JVM简单的按生命周期来进行管理

原文链接:http://blog.csdn.net/zhaozheng7758/article/details/8623562

浅析JVM内存结构和6大区域的更多相关文章

  1. 浅析JVM内存结构和6大区域(转)举例非常好

    内存作为系统中重要的资源,对于系统稳定运行和高效运行起到了关键的作用,Java和C之类的语言不同,不需要开发人员来分配内存和回收内存,而是由JVM来管理对象内存的分配以及对象内存的回收(又称为垃圾回收 ...

  2. 浅析JVM内存结构和6大区域(转)

    其实对于我们一般理解的计算机内存,它算是CPU与计算机打交道最频繁的区域,所有数据都是先经过硬盘至内存,然后由CPU再从内存中获取数据进行处理,又将数据保存到内存,通过分页或分片技术将内存中的数据再f ...

  3. JVM内存结构和6大区域

    摘自 http://www.iteye.com/news/30350 对于我们一般理解的计算机内存,它算是CPU与计算机打交道最频繁的区域,所有数据都是先经过硬盘至内存,然后由CPU再从内存中获取数据 ...

  4. 浅析JVM内存区域及垃圾回收

    一.JVM简介 JVM,全称Java Virtual Machine,即Java虚拟机.以Java作为编程语言所编写的应用程序都是运行在JVM上的.JVM是一种用于计算设备的规范,它是一个虚构出来的计 ...

  5. jvm系列(二):JVM内存结构

    JVM内存结构 所有的Java开发人员可能会遇到这样的困惑?我该为堆内存设置多大空间呢?OutOfMemoryError的异常到底涉及到运行时数据的哪块区域?该怎么解决呢?其实如果你经常解决服务器性能 ...

  6. JVM内存结构

    前言 在Java语言开发过程中,out of memory错误是很常见的一种错误.对于JVM的内存结构有更深入的了解,更更好的帮我们排查此类问题,有效的避免此类问题发生.在JAVA 8中内存结构有进行 ...

  7. 管中窥豹——从对象的生命周期梳理JVM内存结构、GC调优、类加载、AOP编程及性能监控

    如题,本文的宗旨既是透过对象的生命周期,来梳理JVM内存结构及GC相关知识,并辅以AOP及双亲委派机制原理,学习不仅仅是海绵式的吸收学习,还需要自己去分析why,加深对技术的理解和认知,祝大家早日走上 ...

  8. jvm系列二、JVM内存结构

    原文链接:http://www.cnblogs.com/ityouknow/p/5610232.html 所有的Java开发人员可能会遇到这样的困惑?我该为堆内存设置多大空间呢?OutOfMemory ...

  9. JVM内存结构之堆、栈、方法区以及直接内存、堆和栈区别

    JVM内存结构之堆.栈.方法区以及直接内存.堆和栈区别 一.  理解JVM中堆与栈以及方法区 堆(heap):FIFO(队列优先,先进先出):二级缓存:*JVM中只有一个堆区被所有线程所共享:对象和数 ...

  10. JVM活学活用——Jvm内存结构

    Java内存结构: JVM内存结构主要是有三大块:堆内存.方法区和栈.堆内存是JVM中最大的一块由年轻代和老年代组成,而年轻代内存又被分为三部分,Eden空间.From Survivor空间.To S ...

随机推荐

  1. 【YashanDB知识库】主备延迟故障分析方法

    [标题]主备延迟故障分析方法 [问题分类]故障分析 [关键字]Yashandb.主备延迟 [问题描述]当数据库备机出现回放延迟时,需要通过一些手段分析延迟的原因.通过数据库的系统视图或操作系统监控数据 ...

  2. kubernetes删除ns异常状态为:Terminating

    在部署kuboard控制平台的时候,不规范删除,导致ns状态为Terminating [root@master01 ~]# kubectl delete namespace kuboard ^C ro ...

  3. echarts的x轴显示不全的解决办法

    echarts的x轴显示不全的解决办法 一.背景 当x轴类目较多时,label显示时会自动间隔显示,也就是会隐藏掉中间的label,如下图: 二.解决办法 通过设置 xAxis.axisLabel.i ...

  4. Angular 学习笔记 (Angular 12 get started)

    Angular 12 视乎比以往更稳定了. 这里记入一般的 get started 结构和做法. 第 1 步, 创建项目. ng new project --create-application=fa ...

  5. Google 应用出海计划 | 指南针 第六期强势回归启动报名

  6. 系统编程-文件IO-fcntl系统调用

    原型: #include <unistd.h> #include <fcntl.h> int fcntl(int fd, int cmd, ... /* arg */ ); 功 ...

  7. Windows 10 LTSC 2019(1809) WSL 安装 CentOS 7

    1.安装WSL    通过控制面板--程序和功能--启用或关闭WIndows功能,勾选"适用于Linux的Windows子系统".    或者通过管理员权限打开 PowerShel ...

  8. USB type-c CC管脚如何做到正反接检测功能

    USB Type-C 连接器的 CC (Configuration Channel) 管脚用于实现插头方向检测和电源管理.具体来说,USB Type-C 连接器具有两个 CC 管脚:CC1 和 CC2 ...

  9. 【题目全解】ACGO排位赛#13

    ACGO排位赛#13 - 题目解析 感谢大家参加本次排位赛! T1 - 纪元流星雨 题目链接跳转:点击跳转 也没有特别大的难度,手动模拟一下就可以了. 解题步骤 先计算出这个人一生中第一次看到流星雨的 ...

  10. 王树森Attention与Self-Attention学习笔记

    目录 Seq2Seq + Attention Attention的原理 方法一(Used in the original paper) 方法二(more popular,the same to Tra ...