jvm 方法区

方法区在一个jvm实例的内部,类型信息被存储在一个称为方法区的内存逻辑区中。类型信息是由类加载器在类加载时从类文件中提取出来的。类(静态)变量也存储在方法区中。

 

jvm实现的设计者决定了类型信息的内部表现形式。如,多字节变量在类文件是以big-endian存储的,但在加载到方法区后,其存放形式由jvm根据不同的平台来具体定义。

 

jvm在运行应用时要大量使用存储在方法区中的类型信息。在类型信息的表示上,设计者除了要尽可能提高应用的运行效率外,还要考虑空间问题。根据不同的需求,jvm的实现者可以在时间和空间上追求一种平衡。

 

因为方法区是被所有线程共享的,所以必须考虑数据的线程安全。假如两个线程都在试图找lava的类,在lava类还没有被加载的情况下,只应该有一个线程去加载,而另一个线程等待。

 

方法区的大小不必是固定的,jvm可以根据应用的需要动态调整。同样方法区也不必是连续的。方法区可以在堆(甚至是虚拟机自己的堆)中分配。jvm可以允许用户和程序指定方法区的初始大小,最小和最大尺寸。

 

方法区同样存在垃圾收集,因为通过用户定义的类加载器可以动态扩展Java程序,一些类也会成为垃圾。jvm可以回收一个未被引用类所占的空间,以使方法区的空间最小。

 

类型信息

对每个加载的类型,jvm必须在方法区中存储以下类型信息:

一 这个类型的完整有效名

二 这个类型直接父类的完整有效名(除非这个类型是interface或是

     java.lang.Object,两种情况下都没有父类)

三 这个类型的修饰符(public,abstract, final的某个子集)

四 这个类型直接接口的一个有序列表

 

类型名称在java类文件和jvm中都以完整有效名出现。在java源代码中,完整有效名由类的所属包名称加一个".",再加上类名

组成。例如,类Object的所属包为java.lang,那它的完整名称为java.lang.Object,但在类文件里,所有的"."都被

斜杠“/”代替,就成为java/lang/Object。完整有效名在方法区中的表示根据不同的实现而不同。

 

除了以上的基本信息外,jvm还要为每个类型保存以下信息:

类型的常量池( constant pool)

域(Field)信息

方法(Method)信息

除了常量外的所有静态(static)变量

 

常量池

jvm为每个已加载的类型都维护一个常量池。常量池就是这个类型用到的常量的一个有序集合,包括实际的常量(string,integer, 和floating point常量)和对类型,域和方法的符号引用。池中的数据项象数组项一样,是通过索引访问的

因为常量池存储了一个类型所使用到的所有类型,域和方法的符号引用,所以它在java程序的动态链接中起了核心的作用。

 

域信息

jvm必须在方法区中保存类型的所有域的相关信息以及域的声明顺序,

域的相关信息包括:

域名

域类型

域修饰符(public, private, protected,static,finalvolatile, transient的某个子集)

        

方法信息

jvm必须保存所有方法的以下信息,同样域信息一样包括声明顺序

方法名

方法的返回类型(或 void)

方法参数的数量和类型(有序的)

方法的修饰符(public, private, protected, static, final, synchronized, native, abstract的一个子集)除了abstract和native方法外,其他方法还有保存方法的字节码(bytecodes)操作数栈和方法栈帧堆栈以帧为单位保存线程的状态的局部变量区的大小           

异常表

 

类变量(

Class Variables

译者:就是类的静态变量,它只与类相关,所以称为类变量

)

类变量被类的所有实例共享,即使没有类实例时你也可以访问它。这些变量只与类相关,所以在方法区中,它们成为类数据在逻辑上的一部分。在jvm使用一个类之前,它必须在方法区中为每个non-final类变量分配空间。

 

常量(被声明为final的类变量)的处理方法则不同,每个常量都会在常量池中有一个拷贝。non-final类变量被存储在声明它的类信息内,而final类被存储在所有使用它的类信息内。

 

对类加载器的引用

jvm必须知道一个类型是由启动加载器加载的还是由用户类加载器加载的。如果一个类型是由用户类加载器加载的,那么jvm会将这个类加载器的一个引用作为类型信息的一部分保存在方法区中。

 

jvm在动态链接的时候需要这个信息。当解析一个类型到另一个类型的引用的时候,jvm需要保证这两个类型的类加载器是相同的。这对jvm区分名字空间的方式是至关重要的。

 

对Class类的引用

jvm为每个加载的类型(译者:包括类和接口)都创建一个java.lang.Class的实例。而jvm必须以某种方式把Class的这个实例和存储在方法区中的类型数据联系起来。

 

你可以通过Class类的一个静态方法得到这个实例的引用// A method declared in class java.lang.Class:

public static Class forName(String className);

 

假如你调用forName("java.lang.Object"),你会得到与java.lang.Object对应的类对象。你甚至可以通过这个函数得到任何包中的任何已加载的类引用,只要这个类能够被加载到当前的名字空间。如果jvm不能把类加载到当前名字空间,

forName就会抛出ClassNotFoundException。

(译者:熟悉COM的朋友一定会想到,在COM中也有一个称为       类对象(Class Object)的东东,这个类对象主要是实现一种工厂模式,而java由于有了jvm这个中间层,类对象可以很方便的提供更多的信息。这两种类对象都是Singleton的)

 

也可以通过任一对象的getClass()函数得到类对象的引用,getClass被声明在Object类中:

// A method declared in class java.lang.Object:

public final Class getClass();

例如,假如你有一个java.lang.Integer的对象引用,可以激活getClass()得到对应的类引用。

 

通过类对象的引用,你可以在运行中获得相应类存储在方法区中的类型信息,下面是一些Class类提供的方法:

// Some of the methods declared in class java.lang.Class:

public String getName();

public Class getSuperClass();

public boolean isInterface();

public Class[] getInterfaces();

public ClassLoader getClassLoader();

 

这些方法仅能返回已加载类的信息。getName()返回类的完整名,getSuperClass()返回父类的类对象,isInterface ()判断是否是接口。getInterfaces()返回一组类对象,每个类对象对应一个直接父接口。如果没有,则返回一个长度为零的数组。

getClassLoader()返回类加载器的引用,如果是由启动类加载器加载的则返回null所有的这些信息都直接从方法区中获得。

 

方法表

为了提高访问效率,必须仔细的设计存储在方法区中的数据信息结构。除了以上讨论的结构,jvm的实现者还可以添加一些其他的数据结构,如方法表。jvm对每个加载的非虚拟类的类型信息中都添加了一个方法表,方法表是一组对类实例方法的直接引用(包括从父类继承的方法)。jvm可以通过方法表快速激活实例方法。(译者:这里的方法表与C++中的虚拟函数表一样,但java方法全都是virtual的,自然也不用虚拟二字了。正像java宣称没有指针了,其实java里全是指针。更安全只是加了更完备的检查机制,但这都是以牺牲效率为代价的,个人认为java的设计者始终是把安全放在效率之上的,所有java才更适合于网络开发)

 

一个例子

为了显示jvm如何使用方法区中的信息,我们据一个例子,我们

看下面这个类:

class Lava {

     private int speed = 5; // 5 kilometers per hour

     void flow() {

     }

}

 

class Volcano {

     public static void main(String[] args) {

         Lava lava = new Lava();

         lava.flow();

     }

}

下面我们描述一下main()方法的第一条指令的字节码是如何被执行的。不同的jvm实现的差别很大,这里只是其中之一。

 

为了运行这个程序,你以某种方式把“Volcano"传给了jvm。有了这个名字,jvm找到了这个类文件(Volcano.class)并读入,它从类文件提取了类型信息并放在了方法区中,通过解析存在方法区中的字节码,jvm激活了main()方法,在执行时,jvm保持了一个指向当前类(Volcano)常量池的指针。

 

注意jvm在还没有加载Lava类的时候就已经开始执行了。正像大多数的jvm一样,不会等所有类都加载了以后才开始执行,它只会在需要的时候才加载。

 

main()的第一条指令告知jvm为列在常量池第一项的类分配足够的内存。jvm使用指向Volcano常量池的指针找到第一项,发现是一个对Lava类的符号引用,然后它就检查方法区看lava是否已经被加载了。

 

这个符号引用仅仅是类lava的完整有效名”lava“。这里我们看到为了jvm能尽快从一个名称找到一个类,一个良好的数据结构是多么重要。这里jvm的实现者可以采用各种方法,如hash表,查找树等等。同样的算法可以用于Class类的forName()的实现。

 

当jvm发现还没有加载过一个称为"Lava"的类,它就开始查找并加载类文件"Lava.class"。它从类文件中抽取类型信息并放在了方法区中。

 

jvm于是以一个直接指向方法区lava类的指针替换了常量池第一项的符号引用。以后就可以用这个指针快速的找到lava类了。而这个替换过程称为常量池解析(constant pool resolution)。在这里我们替换的是一个native指针。

 

jvm终于开始为新的lava对象分配空间了。这次,jvm仍然需要方法区中的信息。它使用指向lava数据的指针(刚才指向volcano常量池第一项的指针)找到一个lava对象究竟需要多少空间。

 

jvm总能够从存储在方法区中的类型信息知道某类型对象需要的空间。但一个对象在不同的jvm中可能需要不同的空间,而且它的空间分布也是不同的。(译者:这与在C++中,不同的编译器也有不同的对象模型是一个道理)

 

一旦jvm知道了一个Lava对象所要的空间,它就在堆上分配这个空间并把这个实例的变量speed初始化为缺省值0。假如lava的父对象也有实例变量,则也会初始化。

 

当把新生成的lava对象的引用压到栈中,第一条指令也结束了。下面的指令利用这个引用激活java代码把speed变量设为初始值,另外一条指令会用这个引用激活Lava对象的flow()方法。

转载于:https://www.cnblogs.com/Evil-Rebe/p/6505986.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/572680.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言1094题目,基于visual Studio2013解决C语言竞赛题之1094纵横图

/************************************************************************//* 二)程序设计⑴奇阶纵横图n2m1请见填写方法分析1)。 该程序在 数组23题已经完成⑵偶阶纵横图n2(2m1)时,算法分析是把方阵划成A、B、C、D四个小子阵,然后进行多次交换数字来…

c语言考试常考试卷,c语言面试最必考的十道试题,求职必看!!!

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼6、free()函数问:下面的程序会在用户输入’freeze’的时候出问题,而’zebra’则不会,为什么?#include int main(int argc, char *argv[]) {char *ptr (char*)malloc(10);if(NULL ptr){printf(…

Java 导出Excel

前台代码&#xff1a; View Code?12345678910111213141516171819202122232425262728293031323334353637383940414243444546<button class"btn btn-sm btn-success" type"submit" id"detailEp" onclick"return exportCheck(true);"…

android 使用动态的svg资源,在Android中使用SVG作为资源 – victor

victor在Android中使用SVG作为资源。使用这个插件&#xff0c;你可以为SVG定义源文件&#xff0c;它们将会自动在build中光栅化/导入&#xff0c;无需源代码。安装在build.gradle中添加:buildscript {repositories {jcenter()}dependencies {classpath com.trello:victor:0.3.0…

centOS改编码

http://jingyan.baidu.com/article/ab69b270de8b4f2ca7189f1d.html cd /rootvim .bashrcLANG"zh_CN.GBK" :wqsoure.bashrc转载于:https://www.cnblogs.com/finallyliuyu/p/6513587.html

android 键盘 自动消失,android 软键盘 回到键 消失事件 监听

弹出输入法 时 隐藏了 ‘底部状态栏’ 在按 物理 返回键 后&#xff0c; 软键盘消失后 恢复 ‘底部状态栏’public class ImageViewCareIME extends ImageView{public ImageViewCareIME(Context context){super(context);// TODO Auto-generated constructor stub}public stati…

java基础_变量

变量: 数据类型: 基本类型&#xff1a;short/byte(1byte)/char(2byte)-->int(4byte)-->long(8byte)-->float&#xff08;8byte&#xff09;-->double&#xff08;16byte,默认&#xff09;、boolean java变量 从本质上讲&#xff0c;变量其实是内存里面的一小块区域…

android 开机动画尺寸,Android开机Logo动画制作

开机Logo制作1.准备Logo图片准备一张符合尺寸要求(例如&#xff1a;1280x720)的图片&#xff0c;最好是png或jgp。2.用Hitool工具制作镜像文件海思芯片使用的是Hitool工具&#xff0c;打开Hitool&#xff0c;选择HiFastplay&#xff0c;选择右下角的Logo设置&#xff0c;添加图…

18:验证子串

18:验证子串 查看提交统计提问总时间限制: 1000ms内存限制: 65536kB描述输入两个字符串&#xff0c;验证其中一个串是否为另一个串的子串。 输入输入两个字符串&#xff0c; 每个字符串占一行&#xff0c;长度不超过200且不含空格。输出若第一个串s1是第二个串s2的子串&#xf…

android安装过哪些应用程序,如何安装应用程序两次而不干扰Android?

我有一个Android应用程序(让我们称为X),我想创建第二个应用程序X2,但基于另一个应用程序.所以我将清单应用程序名称属性更改为X2也改变了包名...但是当我安装X2时,应用程序X被删除了!我应该更改哪些属性,以便我可以在一台设备上独立安装这两个应用程序.我正在研究eclispe.packa…

android webview es6,Android v 5.0 webview HTML5,CSS3和ES6兼容性

我有一个使用Crosswalk的混合Android应用程序.几个月前我转向Crosswalk,这是一个巨大的生产力提升.我花了很多时间测试不同的Android操作系统版本,并且在HTML5 / CSS3 / ES6实现不完整的情况下遇到的问题要少得多 – 如果我理解正确的话,因为Crosswalk是基于Chromium而不是早期…

ADB 基础命令使用

1.adb shell&#xff08;>2个设备显示&#xff1a;error: more than one device/emulator,仅连接一个设备可用&#xff09; adb -d shell 只运行在真实设备中 adb -e shell 只运行在模拟器中 adb -s "指定设备ID" shell &#xff08;>2个设备可用&#xff09; …

照片边框 app android,Screener App-一手搞定将手机截图加上外框

记得几年前想要在Android手机上截图&#xff0c;得安装类似截图软件与Root 才行&#xff0c;层层的关卡还真不是一般使用者能处理的&#xff0c;如今Android手机大部分都已内置截图功能&#xff0c;对于我撰写App文章来说帮助很大&#xff0c;但有时想要表现哪台手机外框画面时…

java多线程编程相关技术

首先要记住核心一点、多线程事异步的&#xff0c;也就是cpu利用率大幅提高。 Stringbuffer 是线程安全的 stringbuilder是线程不安全的HashTable是线程安全的 HashMap不是线程安全的 2.对象及变量的并发访问下的问题。 方法内的变量因为是方法的私有变量&#xff0…

JAVA补充-抽象类

1.抽象类基本概念 1 package com.neusoft.abstracted;2 /**3 * 抽象类&#xff1a;在class之前加abstract关键字4 * 抽象方法语法&#xff1a; 修饰符 abstract 返回值类型 方法名&#xff08;形参列表&#xff09;&#xff1b;5 * 1.抽象方法的返回值前面有abstract关键…

android谷歌补丁日期,久违的Android更新补丁:多年前的坑,谷歌终于给填上了

3月5日消息&#xff0c;近日谷歌在最新的Android安全公告中称&#xff0c;当前更新的补丁CVE-2020-0069已修复联发科芯片设备的安全漏洞。据了解&#xff0c;联发科曾在2016年左右确认&#xff0c;部分搭载联发科芯片的Android设备存在安全性问题&#xff0c;所涉及的设备数量达…

Linux查看进程并重启服务命令

top -u root 查看系统进程service network restartservice iptables restartservice sshd restartservice nginx restartservice mysqld restart chkconfig转载于:https://www.cnblogs.com/liruning/p/6526487.html

android个人微信支付,Android之微信支付

Android开发中&#xff0c;大多数电商APP都会有支付这么模块&#xff0c;此博客就讲一下微信支付&#xff0c;代码不多&#xff0c;很简单就可以完成&#xff0c;支付宝支付请看博客 Android支付之支付宝封装类先来看看效果图微信支付首先要去微信开发平台申请&#xff0c;得到…

php-函数,数组

自定义函数 function xxx(){ } 函数调用 xxx(); 参数 function xxx($a,$b//1){//当此括号内参数有值时&#xff0c;是默认参数 echo $a$b; } xxx(1,1);//引用括号内的参数 可变个数参数 function xxx(){ echo func_num_args();//输出参数个数 echo array_sum(func_get_args());…

android的图片缩放,Android图片缩放总结及比较

在Android中对大图片进行缩放真的很不尽如人意&#xff0c;不知道是不是我的方法不对。下面我列出3种对图片缩放的方法&#xff0c;并给出相应速度。请高人指教。第一种是BitmapFactory和BitmapFactory.Options。首先&#xff0c;BitmapFactory.Options有几个Fields很有用&…