文档章节

JVM入门学习之 runtime data area

阳光test
 阳光test
发布于 2015/06/11 21:44
字数 2230
阅读 110
收藏 0

        本文主要参考了java6的jvm规范和java8的jvm规范,文档可见:http://docs.oracle.com/javase/specs/jvms/se6/html/VMSpecTOC.doc.htmlhttp://docs.oracle.com/javase/specs/jvms/se8/html/index.html

        这里主要以java6的文档来说,这块的内容详见:http://docs.oracle.com/javase/specs/jvms/se6/html/Overview.doc.html#1732

        runtime data area主要由四部分组成:

        1、pc register : 就是我们常说的pc,指向当前正在执行的代码,由于java是多线程的,而每个核在同一个时刻只有一个线程执行,假设现在我们有线程A和线程B运行在单核的机器上,线程A执行到一半的时候切换到线程B,过了一段时间又切到A,而这个时候系统是需要知道线程A已经执行到什么位置了,所以每一个线程都需要有一个pc register存储当前执行到的代码的地址,如果是native代码,则它是undefined;

        2、method area:存储了类的结构信息等,比如运行时常量池、class属性、方法等,比如常见的字符串String s = "aaaaa";这里的"aaaaa"就是放在运行时常量池中,看着可能比较抽象,等分析字节码的时候就比较清楚了。在Java6时,hotspot vm放在perm gen 去存储,所以很有可能因为工程类过多而导致OOM,可以通过-XX:PermSize和-XX:MaxPermSize来指定大小,不过在Java8中开始采用meta space来存储method area,而它是一个堆外内存,所以不会有这个问题;

        3、stack:这个非常重要,每个线程创建时候都会创建,它存储了stack frame,由于stack只能执行pop、push操作,而每一次方法调用其实就是push一个stack frame,而这个stack frame里面存储了local variable(局部变量表,对应下面代码中的a,b,c变量和this指针)、oprand stack(比如a+b这个操作其实就是入栈a,入栈b然后进行iadd,然后将结果入栈)、    reference to runtime constant pool (这个要分析字节码才比较清楚)、exception table(分析字节码比较清楚)等。


public int test(int a,int b) {
     int c = a + b;
     return c;
}




       4、heap:这个是我们最常用的,存储了绝大部分的对象,比如Test a = new Test();Test对象的实例就存放在heap,为了垃圾回收方便,JVM把这片区域分成了:yong generation(新生代)、tenured generation(老年代)。

          yong generation又被细分为:eden、from survivor(S0)、to survivor(S1),其中S0和S1大小相等,每次系统可用的大小为eden+一个survivor的大小,为什么JVM要把它分成两个survivor,其实是由垃圾收集方法决定的,jvm采用了copying的方式收集yong generation,比如现在eden+S0空间被使用,这个时候yong generation大小不够了,触发了一次YGC,所有存活的对象就会被赶到S1去,然后将S0和eden中的空间全部清理干净,之后系统就直接使用eden+S1来存放对象,S0就变成了备胎。

          在yong generation中存放的的对象,90%以上都是朝生夕死,在下一次YGC的时候就被干掉了,如果这个对象在一次YGC的时候还能够被Gc roots引用到(也就是说这个对象还有用到),那么就将这个对象的年龄+1,当这个对象的年龄达到某一个阀值时,则开始将这个对象转移到tenured。当然,不仅仅是当对象达到年龄的时候才会被转移到tenured generation,当yong generation实在没有空间的情况下也会的,之前我说到过,在YGC时会将还存活的对象从一个survivor复制到另一个survivor,如果存活对象太多,一个survivor放不下的时候,那也会坑。

      在这里,我们用一个简单的Java代码来说明一下,代码如下:

      

public class Test {
	public static void main(String[] args) {
		Test test  = new Test();
		test.test(100L,2);
	}
	public long test(long first,int second) {
		try{
				long third = first + second;
				return third;
		}catch (Exception e){
			e.printStackTrace();
		}
		return 0L;
	}
}

    我们执行javac Test.java编译完之后,执行javap -verbose Test得到 适合人阅读的字节码:

   

Compiled from "Test.java"
public class Test extends java.lang.Object
  SourceFile: "Test.java"
  minor version: 0
  major version: 50
  Constant pool:
const #1 = Method	#9.#22;	//  java/lang/Object."<init>":()V
const #2 = class	#23;	//  Test
const #3 = Method	#2.#22;	//  Test."<init>":()V
const #4 = long	100l;
const #6 = Method	#2.#24;	//  Test.test:(JI)J
const #7 = class	#25;	//  java/lang/Exception
const #8 = Method	#7.#26;	//  java/lang/Exception.printStackTrace:()V
const #9 = class	#27;	//  java/lang/Object
const #10 = Asciz	<init>;
const #11 = Asciz	()V;
const #12 = Asciz	Code;
const #13 = Asciz	LineNumberTable;
const #14 = Asciz	main;
const #15 = Asciz	([Ljava/lang/String;)V;
const #16 = Asciz	test;
const #17 = Asciz	(JI)J;
const #18 = Asciz	StackMapTable;
const #19 = class	#25;	//  java/lang/Exception
const #20 = Asciz	SourceFile;
const #21 = Asciz	Test.java;
const #22 = NameAndType	#10:#11;//  "<init>":()V
const #23 = Asciz	Test;
const #24 = NameAndType	#16:#17;//  test:(JI)J
const #25 = Asciz	java/lang/Exception;
const #26 = NameAndType	#28:#11;//  printStackTrace:()V
const #27 = Asciz	java/lang/Object;
const #28 = Asciz	printStackTrace;

{
public Test();
  Code:
   Stack=1, Locals=1, Args_size=1
   0:	aload_0
   1:	invokespecial	#1; //Method java/lang/Object."<init>":()V
   4:	return
  LineNumberTable: 
   line 1: 0


public static void main(java.lang.String[]);
  Code:
   Stack=4, Locals=2, Args_size=1
   0:	new	#2; //class Test
   3:	dup
   4:	invokespecial	#3; //Method "<init>":()V
   7:	astore_1
   8:	aload_1
   9:	ldc2_w	#4; //long 100l
   12:	iconst_2
   13:	invokevirtual	#6; //Method test:(JI)J
   16:	pop2
   17:	return
  LineNumberTable: 
   line 3: 0
   line 4: 8
   line 5: 17


public long test(long, int);
  Code:
   Stack=4, Locals=6, Args_size=3
   0:	lload_1
   1:	iload_3
   2:	i2l
   3:	ladd
   4:	lstore	4
   6:	lload	4
   8:	lreturn
   9:	astore	4
   11:	aload	4
   13:	invokevirtual	#8; //Method java/lang/Exception.printStackTrace:()V
   16:	lconst_0
   17:	lreturn
  Exception table:
   from   to  target type
     0     8     9   Class java/lang/Exception

  LineNumberTable: 
   line 8: 0
   line 9: 6
   line 10: 9
   line 11: 11
   line 13: 16

  StackMapTable: number_of_entries = 1
   frame_type = 73 /* same_locals_1_stack_item */
     stack = [ class java/lang/Exception ]


}

    

      首先我们看到constant pool中的内容,从const #1到const #28,我们直接看注释,比如const #6,类型是Method,对应着的就是Java代码中的public long test(long first,int second),从这里你就可以理解method area中存放的是啥了把,从method area可以看到类的一个大概,比如类名、方法列表、属性列表等等。

      然后我们看看具体的方法public long test(long first,int second),对应字节码是:

 

public long test(long, int);
  Code:
   Stack=4, Locals=6, Args_size=3
   0:	lload_1
   1:	iload_3
   2:	i2l
   3:	ladd
   4:	lstore	4
   6:	lload	4
   8:	lreturn
   9:	astore	4
   11:	aload	4
   13:	invokevirtual	#8; //Method java/lang/Exception.printStackTrace:()V
   16:	lconst_0
   17:	lreturn
  Exception table:
   from   to  target type
     0     8     9   Class java/lang/Exception

  LineNumberTable: 
   line 8: 0
   line 9: 6
   line 10: 9
   line 11: 11
   line 13: 16

  StackMapTable: number_of_entries = 1
   frame_type = 73 /* same_locals_1_stack_item */
     stack = [ class java/lang/Exception ]


}




    我说过stack frame中存储了local variable,oprand stack等,我们来看看local variable,这里的变量有那些呢,首先参数中有long first,int second这两个,然后还有方法体中的long third和Exception e,那还有吗,其实还有一个,就是this,它是隐含在内的,我们看到字节码中有一个Locals=6,那这个代表什么呢,其实是代表局部变量有6个slot,JVM定义了在32位系统中32bit及小于32位的变量占用一个slot,而64位的占用两个slot,比如int,char,Object的引用,都是1个word,而long,double占用两个slot,多说一点,long,double JVM并不保证它是原子的。那么我们看看现在的局部变量:long first(2 slot) + int second (1 slot) + this (1 slot) + long third (2 slot) + Exception e (1 slot) = 7 slot,什么情况,为什么比字节码中多了一个slot?

     原来JVM会使用slot来复用local variable,怎么理解,很简单,在局部变量表中,如果一个这个变量已经过了作用域,那么后续的局部变量可以复用它的位置,比如这个例子里面的long third = first + second;third这个变量在Exception e这个变量使用时其实已经过了作用域,而它本来占用的local variable的位置为4和5,所以Exception e这个变量占用的是位置4,所以加起来总共locals=6,大家可以将long third = first + second;提到try上面去试试,locals会变成7。

      我们看到上面字节码中有exception table,这个是干啥的,其实很简单,就是说只要字节码0-8,如果出现了异常类型为java/lang/Exception的异常,则跳转到字节码9,这里首先astore 4然后aload 4,都是对局部变量表的下标为4的元素操作,也可以间接证明之前说的slot复用的问题。

      我们现在看看字节码:


13:	invokevirtual	#8; //Method java/lang/Exception.printStackTrace:()V



      这里对应的Java代码就是



e.printStackTrace();



     我们知道#8在const pool中,而方法调用其实是在stack中,我们也就能够理解stack中的referene to runtime constant pool了。


    我是初学者,有写错的地方欢迎大家拍砖!

 



  








© 著作权归作者所有

共有 人打赏支持
阳光test

阳光test

粉丝 543
博文 71
码字总数 91741
作品 1
杭州
程序员
私信 提问
JVM Specification 第一天(JVM数据类型&运行时数据区)

1.The Structure of the Java Virtual Machine 1.1 Data Type 1 The booleanType Although the Java virtual machine defines a boolean type, it only provides very limited support for i......

Kerry_Han
2014/03/18
0
0
ByteBuffer.allocate() vs. allocateDirect

Operating systems perform I/O operations on memory areas. These memory areas, as far as the operating system is concerned, are contiguous sequences of bytes. It's no surprise th......

pczhangtl
2014/03/30
0
0
Java Run-Time Data Areas(Java运行时数据区/内存分配)

Java运行时数据区(内存分配) 本文转载官网 更多相关内容可查看官网 中文翻译可参考 2.5. Run-Time Data Areas The Java Virtual Machine defines various run-time data areas that are use...

lichuangnk
08/19
0
0
JVM系列-Java内存区域(一)

运行时数据区域 Java虚拟机在Java程序执行过程中会把它所管理的内存划分为若干个数据区域,有的区域随着虚拟机进程的启动而存在,有的区域依赖用户线程的启动和结束而建立和销毁。 RUNTIME ...

stefanzhlg
2014/08/29
0
0
Android 之 内存管理

概述 在android的开发中,要时刻主要内存的分配和垃圾回收,因为系统为每一个dalvik虚拟机分配的内存是有限的,在google的G1中,分配的最大堆大小只有16M,后来的机器一般都为24M,实在是少的...

等待流星
2014/03/08
0
0

没有更多内容

加载失败,请刷新页面

加载更多

大数据教程(7.4)HDFS的java客户端API(流处理方式)

博主上一篇博客分享了namenode和datanode的工作原理,本章节将继前面的HDFS的java客户端简单API后深度讲述HDFS流处理API。 场景:博主前面的文章介绍过HDFS上存的大文件会成不同的块存储在不...

em_aaron
昨天
2
0
聊聊storm的window trigger

序 本文主要研究一下storm的window trigger WindowTridentProcessor.prepare storm-core-1.2.2-sources.jar!/org/apache/storm/trident/windowing/WindowTridentProcessor.java public v......

go4it
昨天
6
0
CentOS 生产环境配置

初始配置 对于一般配置来说,不需要安装 epel-release 仓库,本文主要在于希望跟随 RHEL 的配置流程,紧跟红帽公司对于服务器的配置说明。 # yum update 安装 centos-release-scl # yum ins...

clin003
昨天
8
0
GPON网络故障处理手册

导读 为了方便广大网络工作者工作需要,特搜集以下GPON网络处理流程供大家学习参考。开始—初步定为故障—检查光纤状况—检查ONU状态--检查设备运行状态—检查设备数据配置—检查上层设备状态...

问题终结者
昨天
6
0
MariaDB、Apache安装

11月12日任务 11.6 MariaDB安装 11.7/11.8/11.9 Apache安装 1.MariaDB安装 cd /usr/local/src wget https://downloads.mariadb.com/MariaDB/mariadb-10.2.6/bintar-linux-glibc_214-x86_64/......

hhpuppy
昨天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部