深入理解JVM(一)虚拟机内存

一 、前言

JVM是什么,我想诸位肯定都清楚。
好吧,我还是简答说一下JVM即Java虚拟机(够简单吧 233333)。
虽然说,所有抛开操作系统,讲虚拟机的内容,都是耍流氓。但是,贫僧不修善果,就爱杀人放火,就爱耍流氓。好吧,扯远了。
言归正传,JVM这是第三遍重温了。第一遍读时,还是在飞机上读的,就记得飞机上的阳光很刺眼,肚子很难受,从书中汲取的知识很少。第二遍读时,是在做地铁时看完的。地铁很挤,书很好看。如今,距离上次读完,已有一载有余,一年发生了很多事,朋友离开,公司散伙,亲人重病。期间明白了很多道理。一个是,一定要好好的关爱你的亲人。一个是,对于人重要的东西只有两样,健康的身体,以及独立的灵魂。最近读完了史铁生的《我与地坛》对这两点也是感触颇多。
又扯远了。下面进入正题。

二、 内存划分

总体划分如下:
在这里插入图片描述

三、运行时数据区域

运行时数据区域,我们可以分为线程私有的数据区域,与线程共享的数据区域。线程私有,也就是线程内的数据,是能且仅能让创建它的线程访问。线程共享,是任何线程都可以访问共享的此数据。

1、线程私有

(1)程序计数器
  • 程序计数器可以视为当前线程执行的字节码行数指示器。(程序计数器是什么)
  • 多线程运行时,本质上,是线程的轮流切换。这一点,如果对操作系统还有记忆的同学,可能感觉如此之熟悉,是的单核的操作系统中,CPU在执行多任务时,就是将每个任务都执行一点,宏观意义上来讲,就达到了多任务同时进行的感觉。而当虚拟机中多线程执行时,线程执行了一半,就执行其他线程了,又一次回到此线程时,如何确保可以继续执行线程,这里,就是程序计数器的意义所在了。(为什么要有程序计数器)
  • 一个线程有且仅有一个程序计数器。(有第一点和第二点而得出的结论)
(2)java虚拟机栈
[1]栈帧

在每个方法被创建时,同时也会创建一个栈帧。
一个方法被调用到被执行完毕的过程,就是一个栈帧,在虚拟机栈中,从入栈到出栈的过程。

[2]栈帧的数据结构

一个栈帧中包括了局部变量表、操作数栈、动态链接、以及方法出口
这里我们详细的来说一下他的局部变量表
1)存放了基础数据类型。
2)存放了对象的引用
3)存放了returnAddress:指向一条直字节码令的地址

[3]基础数据类型扩展

重温此结的时候,突然想到了基础数据的一个共同点。
他们都可以被转为为int

    public static void main(String[] args) {
        int i = 1;
        short s = 1;
        float f = 1f;
        double d = 1;
        long l = 1L;
        char c = 63;
        byte b2 = 1;
        boolean b =  1;
		System.out.println("输出char>>"+c);
    }

以上代码在编译期间,最后一行,也就是boolean会报错,但是学过c或c++的都知道,bool类型,本质上,true为1,false为0。
而其他的都是可以正常赋值的。
char的赋值,大家可以猜猜,输出的是多少。是63的ASCII值 "?"

输出char>>?

(3)本地方法栈

本地方法栈,他与虚拟机栈类似(数据结构以及功能等方面)
不同的是,虚拟机栈执行的是java方法(编译出的字节码)。而本地方法栈执行的是Native方法。比如:

Thread类中的
private native void start0();

//调用dll或其他文件内方法
 public native static void  Hello();

有些虚拟机,他的本地方法栈与虚拟机栈会合并。

2、线程共享

(1)java堆
  • 堆内的数据,是所有线程共享的。
  • 几乎所有的对象实例都在此存储,因此,java堆又被称为GC堆
(2)方法区
[1]方法区的数据结构

类信息:包括了类的版本、类中的字段、方法、接口以及常量池。常量池在编译期就会确认并生成。
常量。
静态常量。
编译后的代码。

[2] 逻辑上是堆的一部分,但他的别名是非堆。

2、非运行时数据区域

(1)直接内存

NIO使用此块内存,以提高读写性能

四、参考

《深入理解java虚拟机》

posted @ 2019-06-27 17:52  许咸鱼  阅读(748)  评论(1编辑  收藏  举报