深入理解JVM内部结构(转)
- boolean
- byte
- char
- long
- short
- int
- float
- double
- reference
- returnAddress
除了long和double,所有的类型都在局部变量数组中占据一个位置,long及double则占用两个连续的位置(slot),由于它们是双倍的宽度,也即64位大小。
- int i;
编译以后的字节码如下:
- 0: iconst_0 // Push 0 to top of the operand stack
- 1: istore_1 // Pop value from top of operand stack and store as local variable 1
- Young Generation(年轻代),通常被分为Eden和Survivor
- Old Generation(老年代,也叫Tenured Generation)
- Permanent Generation
(2) 内存管理
- 类加载器引用
- 运行时常量池
- 数值常量
- 字段引用
- 方法引用
- 属性值
- 字段数据
- 每个字段
- 名称
- 类型
- Modifiers
- 属性值
- 每个字段
- 方法数据
- 每个方法
- 名称
- 返回类型
- 参数类型
- Modifiers
- 属性值
- 每个方法
- 方法代码
- 每个方法
- 字节码
- 操作对象栈大小
- 局部变量大小
- 局部变量表
- 异常表
- 每个异常处理器
- 起始点
- 结束点
- 处理器代码的PC偏移值
- 捕抓的异常类的常量池索引
- 每个异常处理器
- 每个方法
所有的线程共享相同的方法区,因此方法区数据的存取及动态链接的过程必须是线程安全的。如果两个线程都企图存取同一个类中的字段或方法,但是,此类还没有被加载,则它必须只被加载一次,并且线程必须等到类被加载完成以后才能继续执行。
- ClassFile {
- u4 magic;
- u2 minor_version;
- u2 major_version;
- u2 constant_pool_count;
- cp_info contant_pool[constant_pool_count – 1];
- u2 access_flags;
- u2 this_class;
- u2 super_class;
- u2 interfaces_count;
- u2 interfaces[interfaces_count];
- u2 fields_count;
- field_info fields[fields_count];
- u2 methods_count;
- method_info methods[methods_count];
- u2 attributes_count;
- attribute_info attributes[attributes_count];
- }
如果你想看一个编译完成的类文件的字节码,可以使用命令行工具javap。
- package org.jvminternals;
- public class SimpleClass {
- public void sayHello() {
- System.out.println("Hello");
- }
- }
- public class org.jvminternals.SimpleClass
- SourceFile: "SimpleClass.java"
- minor version: 0
- major version: 51
- flags: ACC_PUBLIC, ACC_SUPER
- Constant pool:
- #1 = Methodref #6.#17 // java/lang/Object."<init>":()V
- #2 = Fieldref #18.#19 // java/lang/System.out:Ljava/io/PrintStream;
- #3 = String #20 // "Hello"
- #4 = Methodref #21.#22 // java/io/PrintStream.println:(Ljava/lang/String;)V
- #5 = Class #23 // org/jvminternals/SimpleClass
- #6 = Class #24 // java/lang/Object
- #7 = Utf8 <init>
- #8 = Utf8 ()V
- #9 = Utf8 Code
- #10 = Utf8 LineNumberTable
- #11 = Utf8 LocalVariableTable
- #12 = Utf8 this
- #13 = Utf8 Lorg/jvminternals/SimpleClass;
- #14 = Utf8 sayHello
- #15 = Utf8 SourceFile
- #16 = Utf8 SimpleClass.java
- #17 = NameAndType #7:#8 // "<init>":()V
- #18 = Class #25 // java/lang/System
- #19 = NameAndType #26:#27 // out:Ljava/io/PrintStream;
- #20 = Utf8 Hello
- #21 = Class #28 // java/io/PrintStream
- #22 = NameAndType #29:#30 // println:(Ljava/lang/String;)V
- #23 = Utf8 org/jvminternals/SimpleClass
- #24 = Utf8 java/lang/Object
- #25 = Utf8 java/lang/System
- #26 = Utf8 out
- #27 = Utf8 Ljava/io/PrintStream;
- #28 = Utf8 java/io/PrintStream
- #29 = Utf8 println
- #30 = Utf8 (Ljava/lang/String;)V
- {
- public org.jvminternals.SimpleClass();
- Signature: ()V
- flags: ACC_PUBLIC
- Code:
- stack=1, locals=1, args_size=1
- 0: aload_0
- 1: invokespecial #1 // Method java/lang/Object."<init>":()V
- 4: return
- LineNumberTable:
- line 3: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 5 0 this Lorg/jvminternals/SimpleClass;
- public void sayHello();
- Signature: ()V
- flags: ACC_PUBLIC
- Code:
- stack=2, locals=1, args_size=1
- 0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
- 3: ldc #3 // String "Hello"
- 5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
- 8: return
- LineNumberTable:
- line 6: 0
- line 7: 8
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 9 0 this Lorg/jvminternals/SimpleClass;
- }
- 常量池, 它提供了与符号表相同的信息,这个将在后面进行详述。
- 方法, 每个方法包含了四个部分:
- 签名及访问标记
- 字节码
- 行号表, 它主要用于为调试器提供信息,行号表指示了每个字节码指令对应的行数,如Java代码中的第六行对应了sayHello方法中的字节码0,第七行对应了字节码8.
- 局部变量表, 它列出了帧中提供的所有局部变量,在本例子中,只有this这一个局部变量。
此类文件中使用到的字节码操作数有:
aload_0
|
此操作码是格式为aload_<n>的操作码组的成员之一,它们都是用于加载一个对象引用到操作
对象栈中. <n>指示了对象在局部变量数组中的位置,可选的数字只能是0,1,2,3之一。还有其它类似的操作
码用于加载数值,而非对象引用。如iload_<n>,lload_<n>, fload_<n>和dload_<n>,其中i是指int类型
l是long,f是float,d是double类型。对于索引值超过3的局部变量,可以使用iload,lload,fload,dload进行
加载。这些操作码都只有一个操作数,用于指定要加载的局部变量的索引。
|
ldc
|
这个指令(操作码)用于将一个运行时常量池中的常量压入操作对象栈中
|
getstatic
|
此指令用于将运行时常量池的静态字段列表中的一个静态值压入到操作对象栈中。
|
invokespecial,
invokevirtual
|
这两个指令属于调用方法的指令组成员之一,调用方法的指令有:invokedynamic,invokestatic,
invokevirtual。在这个类文件中,invokevirtual用于基于对象的类进行方法调用,而invokespecial指令则用
于调用当前类的实例初始化方法,私有方法及父类方法。
|
return
|
此指令时返回型指令组成员之一,其它的还有ireturn,lreturn,freturn,dreturn,areturn及
return。每个指令都是一类返回不同类型数值的返回声明,i是int类型,l是long,f是float,d是
double,a则是对象引用。没有前置类型字符的return则是返回void类型。
|
- 数值型字面值
- 字符串字面值
- 类引用
- 字段引用
- 方法引用
如下面的代码:
- Object foo = new Object();
其对应的字节码如下:
- 0: new #2 // Class java/lang/Object
- 1: dup
- 2: invokespecial #3 // Method java/ lang/Object "<init>"( ) V
- 起始点
- 结束点
- 处理器代码的PC偏移值
- 被捕抓的异常类的常量池索引
如果一个方法定义了一个try-catch或try-finally异常处理器,则一个异常表将会被创建。异常表包含了每个异常处理器或者是finally块的信息,如异常处理应用的范围,那种类型的异常会被处理及异常处理代码所在的位置。
转载地址:http://blog.csdn.net/huaishu/article/details/9844257
深入理解JVM内部结构(转)的更多相关文章
- 深入理解JVM内幕(转)
转自:http://blog.csdn.net/zhoudaxia/article/details/26454421/ 每个Java开发者都知道Java字节码是执行在JRE((Java Runtime ...
- 深入理解JVM内幕:从基本结构到Java 7新特性
转自:http://www.importnew.com/1486.html 每个Java开发者都知道Java字节码是执行在JRE((Java Runtime Environment Java运行时环境 ...
- [译]深入理解JVM
深入理解JVM 原文链接:http://www.cubrid.org/blog/dev-platform/understanding-jvm-internals 每个使用Java的开发者都知道Java ...
- 转:深入理解jvm
深入理解JVM 原文链接:http://www.cubrid.org/blog/dev-platform/understanding-jvm-internals 每个使用Java的开发者都知道Java ...
- 【转】[译]深入理解JVM
http://www.cnblogs.com/enjiex/p/5079338.html 深入理解JVM 原文链接:http://www.cubrid.org/blog/dev-platform/un ...
- 深入理解JVM内幕:从基本结构到Java 7新特性[转]
英文原文:cubrid,编译:ImportNew - 朱伟杰 译文链接:http://www.importnew.com/1486.html [如需转载,请在正文中标注并保留原文链接.译文链接和译者等 ...
- 深入理解 JVM 的内存区域
深入理解运行时数据区 代码示例: 1. JVM 向操作系统申请内存: JVM 第一步就是通过配置参数或者默认配置参数向操作系统申请内存空间,根据内存大小找到具体的内存分配表,然后把内存段的起始地址和终 ...
- 深入理解JVM垃圾收集机制(JDK1.8)
垃圾收集算法 标记-清除算法 最基础的收集算法是"标记-清除"(Mark-Sweep)算法,分两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象. 不足: ...
- 深入理解JVM(一)编译openJDK
此文总结的很不错:https://www.cnblogs.com/ACFLOOD/p/5528035.html 准备openJDK源码和环境 1.在linux和macOS上编译openJDK更加友好, ...
随机推荐
- linux 下echo命令写入文件内容
http://blog.csdn.net/xukai871105/article/details/35834703 echo "Raspberry" > test.txt
- java 面向对象编程--第十四章 多线程编程
1. 多任务处理有两种类型:基于进程和基于线程. 2. 进程是指一种“自包容”的运行程序,由操作系统直接管理,直接运行,有自己的地址空间,每个进程一开启都会消耗内存. 3. 线程是进程内部单一的 ...
- plsql记住登录密码
登录plsql:tools(工具)->preference(首选项)->Login history(登录历史):选择"Store with password"(带口令存 ...
- Android第三方开源对话消息提示框:SweetAlertDialog(sweet-alert-dialog)
Android第三方开源对话消息提示框:SweetAlertDialog(sweet-alert-dialog) Android第三方开源对话消息提示框:SweetAlertDialog(sweet- ...
- Oracle 过程控制语句整理
分支语句/循环语句 v_case ) :; begin then dbms_output.put_line('条件成立'); elsif then then dbms_output.put_line( ...
- javaee 集锦
1.struts2 的配置随版本不同改变,可以使用struts2-blank包生成标准空白项目
- html圆角提示效果
<fieldset> <legend>标题</legend> 内容 </fieldset>
- LibLinear(SVM包)使用说明之(一)README
转自:http://blog.csdn.net/zouxy09/article/details/10947323/ LibLinear(SVM包)使用说明之(一)README zouxy09@qq.c ...
- 蓝桥杯 algo——6 安慰奶牛 (最小生成树)
问题描述 Farmer John变得非常懒,他不想再继续维护供奶牛之间供通行的道路.道路被用来连接N个牧场,牧场被连续地编号为1到N.每一个牧场都是一个奶牛的家.FJ计 划除去P条道路中尽可能多的道路 ...
- C语言中动态分配数组
如何动态的定义及使用数组呢?记得一般用数组的时候都是先指定大小的.当时问老师,老师说是不可以的.后来又问了一位教C++的老师,他告诉我在C++里用new可以做到,一直不用C++,所以也不明白.今天在逛 ...