笔记--深入理解java虚拟机第二版

第一章  走近java

1.JDK(支持java程序开发的最小环境):java程序设计语言,java虚拟机,java API类库

   JRE(支持java程序运行的标准环境):java SE API子集,java虚拟机

2.java平台:Java Card支持java小程序(Applet);Java ME支持java程序在移动端;Java SE面向桌面;Java EE企业级应用

3.JDK1.5:自动装箱、泛型、动态注解、枚举、可变长参数、遍历循环(foreach)

   JDK1.6:动态语言支持、编译API、微型HTTP服务器API、锁与同步、垃圾收集、类加载

   JDK1.7:新的G1收集器、加强对非java语言的调用支持、升级类加载架构

   JDK1.8:Lambda表达式

4.64位比32位额外增加10%~30%的内存消耗,1.6提供了普通对象指针压缩功能,但需要更多代码

第二章  java内存区域与内存溢出异常

1.运行时数据区

   1.1程序计数器:当前线程执行的字节码的行号指示器,线程私有,没有OutOfMemeryError(OOME)异常

        *如果执行的是java方法,计数器记录的是正在执行的虚拟机字节码指令的地址;如果执行的是Native方法,计数器为空

   1.2虚拟机栈:用于存储局部变量表、操作数栈、动态链接、方法出口,线程私有,StackOverFlowError(SOFE)、OOME

   1.3本地方法栈:执行Native方法,OOME、SOFE

   1.4:存放对象实例,线程共享,可连续、可不连续,GC的主要区域,-Xmx堆的最大大小 -Xms堆的初始大小,OOME

   1.5方法区:存储类信息、常量、静态变量,即使编译器编译的代码,线程共享,永久代,可不连续,OOME

   1.6运行时常量池:存编译期生成的字面量和各种引用,运行期间也可能存常量,如String的intern(),OOME

   1.7直接内存:1.4中加入了NIO类,引入了一种基于通道和缓冲区的IO方式,他可以使用Native函数库直接分配堆外内存,然后通过java堆里的DirectoryByteBuffer对象最为这块内存的引用,避免在java堆和Native堆之间来回复制

2.对象的创建(new 反射 克隆 反序列化

   虚拟机接到new–>检查是否被加载过–>没有就加载–>分配内存

   如果内存规整,即占用的内存在一边,空闲的在另一边,指针在分界点,分配内存就是移动指针,分配内存称为“指针碰撞

   如果不规整,维护一个列表,分配空间给对象实例,然后更新列表,称为“空闲列表

   java堆是否规整由GC器是否带有压缩整理功能

   分配完之后初始化为0值

3.对象的内存布局:对象头(Header)、实例数据(Instance Data)、对齐填充(Padding)

   3.1对象头:第一部分用于存储对象自身的运行时数据,另一部分是类型指针确定对象是哪个类的实例

   3.2实例数据:对象存储的有效信息

   3.3对齐填充没意义,起占位符的作用

4.对象的访问定位:句柄、直接指针

   句柄:在堆里划出一部分内存作为句柄池,对象名指向句柄,句柄包含对象实例数据和类型数据的地址信息

   *优点:GC时对象位置移动时,不用改引用 

  直接指针:对象名指向new

   *优点:速度快

5.线程请求的栈深度大于虚拟机允许的最大深度,抛StackOverFlowError

   虚拟机栈在扩展栈时无法申请到足够的内存空间,抛OutOfMemeryError

   *单线程下,无论栈太小还是内存不足,都抛StackOverFlowError

第三章  垃圾收集器与内存分配策略

1.判断对象存亡方法

   1.1.引用计数法

   给对象添加一个引用计数器,每当有一个地方引用它,就加1,引用失效,就减1,为0时,对象不能再使用很难解决互相引用的问题

   1.2.可达性分析算法

   通过一系列被称为“GC Roots”的对象作为起点,当一个对象到GC Roots没有任何引用链时,该对象不可用

   *GC Roots包括:虚拟机栈中引用的对象;方法区中类静态属性引用的对象;方法区中常量引用的对象;本地方法栈中JNI引用的对象

2.引用

   强引用(GC不会回收)、软引用(有用但非必须)、弱引用(只能活到下次GC前)、虚引用

3.GC过程

   可达性分析后没有引用链–>标记并筛选–>筛选条件是该对象是否有必要执行finalize()方法–>对象没有覆盖finalize()方法或已经被虚拟机调用过,则没必要执行finalize()–>有必要执行,把对象放入F-Queue队列,稍后执行一个虚拟机自动建立的,低优先级的Finalizer线程,去触发finalize()方法–>GC对对象第二次标记–>如果二次标记前被引用过,就死不了,否则被回收

4.GC算法

   4.1.标记-清除算法:*缺点:效率低;产生不连续的内存碎片

   4.2.复制算法:分代算法

   4.3.标记-整理算法:标记后,让存活的向一段移动,其他的清掉,保证内存连续

5.何时何地GC

   5.1.安全点:程序执行到安全点时才能执行GC

   *选择标准:可以让程序长时间执行的地方

   主动式中断:GC需要中断线程的时候,不去直接对线程操作,而是设置一个标志,线程轮询这个标志,标志为真时自己中断

   5.2.安全区域:一段代码片段中,引用关系不会发生改变,在这里GC是安全的

6.分配策略

   优先进入Eden;

   大对象直接进入老年代;

   年龄到一定程度(默认15岁)进入老年代;

   survivor中相同年龄所有对象大小的和大于等于survivor的一半,这些对象以及比它们年龄大的对象进入老年代

第六章  类文件结构

1.Class文件是一组以8位字节为基础单位的二进制流,各个数据项目紧密排列,没有分隔符
   伪结构:无符号数和表
2.(未完待续)

第七章  虚拟机类加载机制

1.把描述类的数据从Class文件加载到内存,对数据进行校验,转换解析,初始化,最终形成虚拟机直接使用的java类型
2.通过子类引用父类的静态字段,不会导致子类初始化;通过数组定义来引用类,不会初始化;常量在编译阶段就进入常量池,不会引起初始化
3.比较两个类相等,只有这两个类是由同一个类加载器加载的才有意义。
4.启动类加载器Bootstrap ClassLoader、扩展类加载器Extension ClassLoader、应用程序类加载器Application ClassLoader
5.双亲委派模型,父子关系由组合来实现,一个类加载器接受请求后,先请求父加载器,最终传送到启动加载器,只有当父类解决不了,才由子类自己加载

第八章  虚拟机字节码执行引擎

1.执行引擎执行java代码有两种方法:解释执行(通过解释器执行),编译执行(即时编译器产生的本地代码执行)

第十章  早期优化

1.泛型包括:泛型类、泛型接口、泛型方法
2.两个方法名和参数相同,返回值不同,也可以存在一个Class文件中
3.自动装箱的陷阱
Integer a = 1; 
Integer b = 2;

Integer c = 3; 
Integer d = 3;
Integer e = 321; 
Integer f = 321;
Long g = 3L;
c == d; // true      e == f; // false Integer在没有基本运算的状态下,不会自动拆箱,范围是-128~127
c == (a + b); // true      c.equals(a + b); // true
g == (a + b); // true      g.equals(a + b); // false 类型不同

第十二章  晚期优化

1.即时编译器:在运行时,虚拟机将代码编译成与本地平台相关的机器码,并进行各种层次的优化






































    原文作者:java虚拟机
    原文地址: https://blog.csdn.net/zhulurensheng/article/details/78486428
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞