看一遍就会的类加载机制(二)

上一篇文章说到了类是由谁加载到jvm中https://www.jianshu.com/p/63fe0ad13276
,这次来说一说加载进来之后怎么存放。
先不管jvm是如何设计区域划分的规则的,我们自己来设计一下。
已知jvm中需要存放类的信息和类的实例对象。

1、那就先划分成两块区域:“类信息区”+“对象区”

一块放类信息(比如类中的各种变量,常量,方法)简称“类信息区”,一块只放对象(new出来的实例)简称“对象区”

那这样分行不行呢?来分析一下
思路:不管是类还是对象,它们的作用都是被jvm操作使用的。那么具体看看在使用过程中,这样分配会不会出现什么问题。

public class Apple {
    private int name;
    private static int age ;
    private final int color = 0;

    public void sweet(){
        int smell;
    }
    public void method_A(){
        method_B();
    } 
    public void method_B(){
    }
    public native String getStr(){
    }
}

对Apple这个类中所有内容一个一个分析:

  • 首先是非静态成员变量private int name:

它被调用的方式是:new Apple().name,如果按照我们上面的划分规则,变量是在类信息区的,那么它的调用过程就需要从对象区“出来”,然后“进入”到类信息区中找到name,并且如果new了多个Apple对象,那还要知道是多个对象和多个name的对应关系,假如name和apple对象是在一个区域多好啊,那我们改一下规则,把非静态成员变量放入“对象区”

  • 然后,静态的成员变量private static int age:

调用方式如何?Apple.age,或者new对象这两种方式都可以调用到,那么放到哪个区域呢?我们来看一下static关键字的意义:方便在没有创建对象的情况下来进行调用。那我觉得和类放在一起比较好,静态成员变量放入“类信息区”

  • 接着private final int color=0是一个常量:

常量的意义在于共享,两块区域目前都支持共享,不知道该放哪,就再开一块区域放吧,就叫”常量区“。
看样刚才两块区域的划分方式不行了,需要划分成三块区域。

2、新增第三块区域:”常量区“

"常量区"用来存放常量。

  • 继续往下看,sweet()是一个方法:

调用它的方式是new Apple().sweet(),那就放对象区?那如果加了static的话就放类信息区?难道又再开一片区域?有点不好决定,暂且放“对象区”,先存疑

  • 然后sweet方法内部有一个非静态变量smell:

是在方法中,所以和方法放在一起没毛病把,那也暂且放“对象区”,先存疑。

好,现在来重新总结下:
“类信息区”包含静态变量
“对象区”包含实例+非静态变量+方法(存疑)和方法内变量(存疑);
”常量区“包含”常量“

现在,把存疑的再拎出来分析:方法。
方法被执行的话是谁执行呢?
已知Jvm启动以后是一个java进程,我们都知道main函数是程序执行起点,jvm通过创建一个线程来执行main函数,同理其他方法也都是由各个线程来执行。

  • 好,我们知道方法是被线程执行,那线程要执行方法,总得给线程一块场地用来执行吧

那么在“类信息区”和”对象区“中哪块区域执行比较好呢?两块地方都是用来存储的,好像都不太合适,那还是单独开一块空间用来执行吧,简称”执行区“

3、新增第四块区域:”执行区“

”执行区“用来让线程执行方法。

现在我们把方法sweet()移到新划分的”执行区“中,那么方法中的smell也一起移到”执行区“中,上面的存疑解除,于是sweet()方法的一生(执行开始到结束)都在”执行区“了。

再继续往下看method_Amethod_B两个方法,这两个方法有调用关系。A方法在执行过程中,去调用了B方法,那A什么时候执行完毕呢?当然是得等B执行完毕后A才能执行完毕,这就好比羽毛球筒,最先放进去的羽毛球肯定是最后一个才能被拿出来使用,这种场景有一个术语叫做”栈“,于是为了专业点,我们把”执行区“名字换一下,叫做”栈区“,那方法和方法内的局部变量所在区域就是”栈区“。是不是这样呢?官方文档有说明:https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.5.2 官网上说每一个jvm线程都有一个私有的虚拟机栈,栈中存放的是栈帧。如果你看过我的上一篇文章《计算机组成原理学习记录》,就会知道栈的最小单元叫做栈帧(7、cpu是如何执行函数调用的?https://www.jianshu.com/p/f0b966b94b69),我们假设一个方法表示一个栈帧,方法开始执行对应的动作是进栈,方法执行结束对应的动作是出栈,那么我们的假设是否正确呢?官网文档也有说明:https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.6
官网上说一个栈帧是在一个方法被执行时创建的。

4、为了更专业,"执行区"名字改为”栈区“
  • 再看getStr()这个方法,有一个修饰符native

说明这个方法会去调用c语言的一个代码,那么它本质上也是一个方法,但是是一个”本地方法“,我们把它也放在”栈区“可以吗?我觉得是可以的,但是jvm告诉我们,它对本地方法中用到的语言、方式、数据结构没有强制规定,而”栈区“运行的方法又都是有规定的:java字节码。那我觉得还是把这两块区分一下比较好,所以我们再开辟一块区域就叫做”本地方法区“。(PS:Sun HotSpot虚拟机就是把本地方法栈和虚拟机栈合在一起的)

5、新增第五块区域:”本地方法区“

好现在方法的区域已经安排的明明白白了,线程T可以执行A方法,可以执行B方法,可以执行sweet方法,三个方法都交给T线程执行效率好像有点慢哦?

  • 我们知道jvm运行是可以多线程执行

如果看过我上一篇文章《计算机组成原理学习记录》就会知道CPU通过一些策略可以让自己看起来是在同时运行多个线程(27、CPU继续优化:超线程和SIMD https://www.jianshu.com/p/f0b966b94b69)。
CPU在线程A指令的流水线停顿时,切换到线程B去执行指令,也就是说在方法的执行过程中,CPU很有可能会被别的线程拿去使用。
那么还是看上面的例子,假设有两个线程,分别用来执行方法sweet和方法A,方法sweet的线程还没执行完毕,CPU被切换到方法A的线程,执行了一会方法A,CPU又切回到方法sweet,那么这时候sweet这个方法将如何继续执行,好像只能从头开始执行,因为刚才CPU被抢走的时候,没人知道sweet执行到哪里了。
不过从头开始执行那不是太low了?
所以应该有一个计数器一样的东西来记录下线程在CPU被抢走时执行的位置信息,那计数器的信息保存在哪里呢?肯定是和线程在一起呀,并且每一个线程都需要一个这个区域,那就存放在”栈区“,真的是这样吗?
官方文档其实给这个区域单独划分了一块区域,叫做”pc寄存器“,为什么单独划分,因为这个计数器干的事就是CPU中PC寄存器干的事啊!不知道PC寄存器干什么的同学还是去我的另一篇文章《计算机组成原理学习记录》中搜索PC寄存器关键字。
扩展思考:当执行本地方法时,会保存这个位置信息吗?

6、新增第6块区域:”PC寄存器“

类信息、实例、变量、常量、方法全部都分析完毕,我们一共分了6块区域:

“类信息区”包含静态变量
“对象区”包含实例+非静态变量;
”常量区“包含”常量“
”栈区“包含线程执行的”方法“
”本地方法区“包含线程执行的”本地方法“
”PC寄存器“包含线程执行的指令位置

来看看官网的划分:
https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.5

2.5.1. The pc Register

对应我们”PC寄存器“
The Java Virtual Machine can support many threads of execution at once (JLS §17). Each Java Virtual Machine thread has its own pc (program counter) register. At any point, each Java Virtual Machine thread is executing the code of a single method, namely the current method (§2.6) for that thread. If that method is not native, the pc register contains the address of the Java Virtual Machine instruction currently being executed. If the method currently being executed by the thread is native, the value of the Java Virtual Machine's pc register is undefined. The Java Virtual Machine's pc register is wide enough to hold a returnAddress or a native pointer on the specific platform.

2.5.2. Java Virtual Machine Stacks

对应我们”栈区“

Each Java Virtual Machine thread has a private Java Virtual Machine stack, created at the same time as the thread. A Java Virtual Machine stack stores frames (§2.6). A Java Virtual Machine stack is analogous to the stack of a conventional language such as C: it holds local variables and partial results, and plays a part in method invocation and return. Because the Java Virtual Machine stack is never manipulated directly except to push and pop frames, frames may be heap allocated. The memory for a Java Virtual Machine stack does not need to be contiguous.

In the First Edition of The Java® Virtual Machine Specification, the Java Virtual Machine stack was known as the Java stack.

This specification permits Java Virtual Machine stacks either to be of a fixed size or to dynamically expand and contract as required by the computation. If the Java Virtual Machine stacks are of a fixed size, the size of each Java Virtual Machine stack may be chosen independently when that stack is created.

A Java Virtual Machine implementation may provide the programmer or the user control over the initial size of Java Virtual Machine stacks, as well as, in the case of dynamically expanding or contracting Java Virtual Machine stacks, control over the maximum and minimum sizes.

The following exceptional conditions are associated with Java Virtual Machine stacks:

  • If the computation in a thread requires a larger Java Virtual Machine stack than is permitted, the Java Virtual Machine throws a StackOverflowError.

  • If Java Virtual Machine stacks can be dynamically expanded, and expansion is attempted but insufficient memory can be made available to effect the expansion, or if insufficient memory can be made available to create the initial Java Virtual Machine stack for a new thread, the Java Virtual Machine throws an OutOfMemoryError.

2.5.3. Heap

对应我们”对象区“
The Java Virtual Machine has a heap that is shared among all Java Virtual Machine threads. The heap is the run-time data area from which memory for all class instances and arrays is allocated.

The heap is created on virtual machine start-up. Heap storage for objects is reclaimed by an automatic storage management system (known as a garbage collector); objects are never explicitly deallocated. The Java Virtual Machine assumes no particular type of automatic storage management system, and the storage management technique may be chosen according to the implementor's system requirements. The heap may be of a fixed size or may be expanded as required by the computation and may be contracted if a larger heap becomes unnecessary. The memory for the heap does not need to be contiguous.

A Java Virtual Machine implementation may provide the programmer or the user control over the initial size of the heap, as well as, if the heap can be dynamically expanded or contracted, control over the maximum and minimum heap size.

The following exceptional condition is associated with the heap:

  • If a computation requires more heap than can be made available by the automatic storage management system, the Java Virtual Machine throws an OutOfMemoryError.

2.5.4. Method Area

对应我们”类信息区“
The Java Virtual Machine has a method area that is shared among all Java Virtual Machine threads. The method area is analogous to the storage area for compiled code of a conventional language or analogous to the "text" segment in an operating system process. It stores per-class structures such as the run-time constant pool, field and method data, and the code for methods and constructors, including the special methods (§2.9) used in class and instance initialization and interface initialization.

The method area is created on virtual machine start-up. Although the method area is logically part of the heap, simple implementations may choose not to either garbage collect or compact it. This specification does not mandate the location of the method area or the policies used to manage compiled code. The method area may be of a fixed size or may be expanded as required by the computation and may be contracted if a larger method area becomes unnecessary. The memory for the method area does not need to be contiguous.

A Java Virtual Machine implementation may provide the programmer or the user control over the initial size of the method area, as well as, in the case of a varying-size method area, control over the maximum and minimum method area size.

The following exceptional condition is associated with the method area:

  • If memory in the method area cannot be made available to satisfy an allocation request, the Java Virtual Machine throws an OutOfMemoryError.

2.5.5. Run-Time Constant Pool

对应我们”常量区“
A run-time constant pool is a per-class or per-interface run-time representation of the constant_pool table in a class file (§4.4). It contains several kinds of constants, ranging from numeric literals known at compile-time to method and field references that must be resolved at run-time. The run-time constant pool serves a function similar to that of a symbol table for a conventional programming language, although it contains a wider range of data than a typical symbol table.

Each run-time constant pool is allocated from the Java Virtual Machine's method area (§2.5.4). The run-time constant pool for a class or interface is constructed when the class or interface is created (§5.3) by the Java Virtual Machine.

The following exceptional condition is associated with the construction of the run-time constant pool for a class or interface:

  • When creating a class or interface, if the construction of the run-time constant pool requires more memory than can be made available in the method area of the Java Virtual Machine, the Java Virtual Machine throws an OutOfMemoryError.

See §5 (Loading, Linking, and Initializing) for information about the construction of the run-time constant pool.

2.5.6. Native Method Stacks

对应我们”本地方法区“
An implementation of the Java Virtual Machine may use conventional stacks, colloquially called "C stacks," to support native methods (methods written in a language other than the Java programming language). Native method stacks may also be used by the implementation of an interpreter for the Java Virtual Machine's instruction set in a language such as C. Java Virtual Machine implementations that cannot load native methods and that do not themselves rely on conventional stacks need not supply native method stacks. If supplied, native method stacks are typically allocated per thread when each thread is created.

This specification permits native method stacks either to be of a fixed size or to dynamically expand and contract as required by the computation. If the native method stacks are of a fixed size, the size of each native method stack may be chosen independently when that stack is created.

A Java Virtual Machine implementation may provide the programmer or the user control over the initial size of the native method stacks, as well as, in the case of varying-size native method stacks, control over the maximum and minimum method stack sizes.

The following exceptional conditions are associated with native method stacks:

  • If the computation in a thread requires a larger native method stack than is permitted, the Java Virtual Machine throws a StackOverflowError.

  • If native method stacks can be dynamically expanded and native method stack expansion is attempted but insufficient memory can be made available, or if insufficient memory can be made available to create the initial native method stack for a new thread, the Java Virtual Machine throws an OutOfMemoryError.

文章结束语:
PS 在看运行时常量池时https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.5.5
发现Integer有自己的常量池:-127到128,也就是8个字节包含正负。(才保存这一点量,真抠哈哈)

image.png

Double没有。
image.png

在想Double没有是不是因为浮点型精度太多了,干脆就一个都不存了。
所以你如果用-127到128区间内的Integer对象来做==比较,返回结果是true,因为走到了常量池中,是一个内存地址。超过这个区间就是false了。
而Double的==一直是false。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335