java虚拟机基础

# 1. what is jvm?

​ jvm大家了解到的Java Virtual Machine。**java的跨平台,一次编译,到处执行**。每一种操作系统,执行相关程序的时候,因为操作系统环境的不同,会造成代码不能跨平台执行。而java可以做到,原因在哪里?**就在于不同操作系统有不同版本的jvm**。

语言的执行过程:

​ 源代码(.java)----->编译(字节码 .class)----->解释(成为机器码,01010100110)---->机器码

jvm发展史

1、Sun Classic

只能使用纯解释器来执行java代码,若要使用jit编译器则要使用第三方外挂,且使用了jit则解释器就不执行工作了,此时的编译器不智能,编译器不得不对每一个方法、每一行代码都进行编译,而无论它们执行的频率是否具有编译的价值。

2、Exact Vm

支持编译器和解释器混合工作模式,使用了准确试内存管理虚拟机可以知道内存中,某个位置的具体数据类型 由于使用了准确式内存管理,Exact VM可以抛弃以前Classic VM基于handle的对象查找方式每次定位对象都少了一次间接查找的开销,提升执行性能。

3、Sun HotSpot VM

(1)、可以通过执行计数器找出最具有编译价值的代码,根据执行计数器判断是否达到阈值,没达到就解释执行,否则提交编译请求通知jit编译器以方法为单位进行编译

(2)、通过编译器与解释器恰当地协同工作,可以在最优的程序响应时间与最佳执行性能中取得平衡,即编译的时间压力也会相对减少,这样有助于引进更多的代码优化技术输出质量更高的本地代码

jvm的内存区域划分

1、运行时区域划分

jvm 运行时内存区域分为两种,线程隔离和线程共享

线程隔离分为:栈和程序计数器

线程共享分为:堆和方法区

各个区域介绍

1、程序计数器

是当前线程所执行的字节码行号指示器,字节码解释器工作就是通过改变计数器的值来选取要执行的字节码指令

每条线程都需要有一个独立的程序计数器,各个线程之间计数器互不影响,独立存储

如果线程正在执行的是Native方法,这个计数器值则为空

2、栈

java虚拟机栈、本地方法栈

java虚拟机栈为虚拟机执行java方法(字节码)服务,

本地方法栈为虚拟机使用到的Native服务

每个方法执行的同时会创建一个栈帧用于存储局部变量表,操作数栈,动态链接,方法出等信息,每个方法从调用到执行完成就是一个栈帧的入栈到出栈的过程局部变量表所需的内存空间在编译期间完成分配,其中64位的long和double类型的数据会占2个局部变量空间,其余的数据类型只占用1个。当进入一个方法时,这个方法需要在帧中分配多大的局部变量空间是完全确定的,在方法运行期间不会改变局部变量表的大小。

​ 数栈也要操作栈,主要是在方法计算时存放的栈

3、堆

堆就是存放对象实例的几乎所有的对象实例都在这里分配内存

Java堆是垃圾收集器管理的主要区域;内存回收的角度来看Java堆中还可以细分为:**新生代和老年代**;新生代细致一点的有**Eden空间**、**From Survivor空间**、**To Survivor空间**。这两块survivor空间大小一致。

java堆的内存空间可以是固定的也可以是可扩展的通过通过**-Xmx设置最大内存和-Xms设置初始内存**)

例如java -Xms10m -Xmx100m Hello

4、方法区

方法区又叫静态区:用于存储已被虚拟机加载的类信息,常量池,静态变量,即是编译器编译器编译器编译后的代码等数据别名叫non-heap非堆

java虚拟机中,方法区除了不需要连续的内存和选择固定大小或可扩展外还可以选择不实现垃圾回收

这区域的内存回收目标主要是针对常量池的回收和对类型的卸载,条件相当苛刻。

在jdk1.7中永久代的配置参数-XX:PermSize5m(初始化永久代内存大小),-XX:MaxPermSize10m(最大永久代内存大小)

​ 在jdk1.8中Metaspace的配置参数:-XX:MetaspaceSize=10m(初始化大小),-XX:MaxMetaspaceSize=10m(最大大小)

java中的常量池技术,是为了方便快捷地创建某些对象而出现的,当需要一个对象时,就可以从池中取一个出来(如果池中没有则创建一个),在需要重复创建相等变量时节省了很多时间

异常oom

程序计数器

没有指定任何OutOfMemoryError情况

java虚拟机栈\本地方法栈区域

如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常

如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError异常

报错后dump出信息: -XX:+HeapDumpOnOutOfMemoryError

-Xms5m -Xmx5m -XX:+HeapDumpOnOutOfMemoryError

方法区

当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常

对象是的引用和可达性分析

1、对象的四类引用

java的引用分为 :强引用、软引用、弱引用、虚引用四种引用强度依次减弱

强引用在程序中的正常创建对象的引用,垃圾回收器不会回收强引用对象

2、软引用 有用但非必须地对象jdk中提供了SoftReference类来实现软引用;系统在发生内存溢出异常之前,会把只被软引用的对象进行回收。

​ 用途?可以做缓存。

3、弱引用 非必须对象了WeakReference类来实现软引用,比软引用弱一些;垃圾回收不论内存是否不足都会回收只被弱引用关联的对象。

4、虚引用 对被引用对象的生存时间不影响;无法通过虚引用来取得一个对象实例;为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知;jdk提供PhantomReference类来实现虚引用

例如

```

/**

* Java引用分为:强引用>软引用>弱引用>虚引用

*

*/

public class ReferenceTest {

    public static void main(String[] args) {

        System.out.println("===========强引用========");

        //强引用

        Person p = new Person();

        System.gc();//手动执行垃圾回收

        System.out.println(p);

        //软引用

        System.out.println("===========软引用========");

        SoftReference<Person> sp = new SoftReference<Person>(new Person());

        System.gc();

        System.out.println(sp.get());

        System.out.println("---------------软引用在内存溢出的表现-------------------------");

        try {

            List<HeapOOM.OOMObject> list = new ArrayList<HeapOOM.OOMObject>();

            while (true) {

                list.add(new HeapOOM.OOMObject());

            }

        } finally {

            System.out.println("内存溢出之后的软引用是否存在:");

            System.out.println(sp.get());

            System.out.println("---------------软引用在内存溢出的表现-------------------------");

            //弱引用

            System.out.println("===========弱引用========");

            WeakReference<Person> wp = new WeakReference<Person>(new Person());

            System.gc();

            System.out.println(wp.get());

            System.out.println("===========虚引用========");

            //虚引用

            ReferenceQueue<Person> referenceQueue = new ReferenceQueue<Person>();

            Person person = new Person();

            PhantomReference<Person> pp = new PhantomReference<Person>(person, referenceQueue);

            person = null;

            System.out.println(referenceQueue.poll());

            System.gc();

            System.out.println(pp.get());

            try {

                //gc后等1秒看结果

                Thread.sleep(1000);

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

            System.out.println(referenceQueue.poll());

            System.out.println("===================================");

            Properties properties = System.getProperties();

            for (Map.Entry<Object, Object> me : properties.entrySet()) {

                System.out.println(me.getKey() + "=" + me.getValue());

            }

            System.out.println("=================获取传递个JVM的参数=========================");

            System.out.println(System.getProperty("zookeeper.root.logger"));//-Dzookeeper.root.logger=INFO,stdout,R

            Person p1 = new Person();

            Person nP = p1;//

            p1 = null;

            System.out.println(nP);

        }

    }

}

class Person {

    String name = "张三";

    @Override

    public String toString() {

        return name;

    }

}

```

引用的可达性分析

判定一个对象不被引用的方法就是可达性分析在可达性分析之前还有一种方式判定对象是否被引用====》引用计数器法

引用计数器法

引用计数算法基本思想:给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用的。

可达性分析

通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连(即不可达)时,则证明此对象是不可用的

常见的gc root对象:

1. 虚拟机栈(栈帧中的本地变量表)中引用的对象。

2. 方法区中类静态属性引用的对象。

3. 方法区中常量引用的对象。

4. 本地方法栈中JNI(Java Native Interface即一般说的Native方法)引用的对象。

垃圾回收的执行过程

如果我们判定一个对象不可达,就应该将该对象进行gc垃圾回收掉,但是jvm在进行垃圾回收之前会对这些对象进行一轮的筛选,如果相关对象此时重新和引用链的对象建立起了关联,那么是可以逃脱被gc掉的命运,但是不是所有的对象都有着特权,只有我们在编写类的时候,复写Object类中的一个方法**finalize()**,也就是说在该方法重重新建立了引用,就可以起死回生

不可达的对象真正死亡需要两次标记:

​ 当不可达时标记第一次标记,当**对象覆盖finalize()方法并且finalize()方法没有被虚拟机调用过**,此对象将会放置在一个叫做F-Queue的队列之中,稍后由一个由虚拟机自动建立的、低优先级的Finalizer线程去触发这个方法,但并不承诺会等待它运行结束再执行垃圾回收。

​ finalize()方法是对象逃脱死亡命运的最后一次机会,稍后GC将对F-Queue中的对象进行第二次小规模的标记,如果对象要在finalize()中重新与引用链上的任何一个对象建立关联那么他被移除出“即将回收”的集合,否则就被回收了。

例如

```

public class FinalizeObj {

    public static FinalizeObj obj;

    @Override

    protected void finalize() throws Throwable {

        super.finalize();

        System.out.println("FinalizeObj finalize called !!!");

        obj = this;//在finalize方法中复活对象

    }

    @Override

    public String toString() {

        return "I am FinalizeObj";

    }

    public static void main(String[] args) throws InterruptedException {

        obj = new FinalizeObj();

        obj = null; //将obj设为null

        System.gc();//垃圾回收

        System.out.println(":-------------------");

        Thread.sleep(1000);//

        if(obj == null) {

            System.out.println("obj is null");

        } else {

            System.out.println("obj is alive");

        }

        System.out.println("第2次调用gc后");

        obj = null;//由于obj被复活,此处再次将obj设为null

        System.gc();//再次gc

        Thread.sleep(1000);

        if(obj == null) {

            //对象的finalize方法仅仅会被调用一次,所以可以预见再次设置obj为null后,obj会被垃圾回收,该语句会被调用

            System.out.println("obj is null");

        } else {

            System.out.println("obj is alive");

        }

    }

}

```

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

推荐阅读更多精彩内容