jvm读书笔记

来源:互联网 发布:nat穿越java实现 编辑:程序博客网 时间:2024/06/07 05:30

最近又看了一下深入理解jvm一书,感觉和上次看又有了一些新的体理解,简单记录下自己认为比较重要的部分,想更加深入了解的读者,还是看原书比较好,十分推荐,一本很好的书

JVM

屏蔽了与具体操作系统平台相关的信息,实现了跨平台.
jvm与os无关,实现了跨平台

虚拟机内存

java虚拟机数据区

  • PC 程序计数器
  • 虚拟机栈
    平时说的栈内存.根据局部变量表,存放局部变量.进入方法之前就确定了大小,不会再改变
    局部变量存放在栈内存。随着方法的消失而消失。栈内存来得快去得快,主要考虑运行程序。
    局部变量必须初始化

    • 本地方法栈
      类似
  • 堆内存

    • java虚拟机中最大的一块.存放的是对象.所有的对象instance都在这里分配.
    • 是GC管理的主要区域.

    • 方法区
      存放已经被虚拟机加载的类信息,常量,静态变量,编译后的代码等

    • 运行常量池
      存放编译期间生成的引用等.
    • 操作对象
      java通过栈上的reference操作堆上的具体对象.引用操作堆的方法:
  • 句柄方式 在堆内存中化出一片句柄池,引用中存放的是句柄池中各个句柄的地址。句柄中包含了对象实例数据和数据的的集体地址信息。在对象移动的时间只需要修改堆内存中句柄池的句柄的信息,不需要修改引用的信息。
  • 指针方式 直接操作堆中的对象。(hotpot采用)
    更快,节省了一次指针定位的时间开销。

垃圾回收机制

  • 哪些内存需要回收
  • 什么时候回收内存
  • 如何回收

gcroot

gcroot不可达.引用链
引用链。当一个对象到gcroots没有任何一个引用链可以达到的时候,认为应该回收他

  • 强引用 只要他在,就不回收。
  • 软引用 即将发生内存溢出的时候。回收该部分内存,如果还是不够,报内存溢出异常。
  • 弱引用 只要gc,就要回收
  • 虚引用

当gc不可达的时候,不会立刻回收,还要再经过一次判断,才决定回收
第一次gc不可达或,会进行一次筛选,筛选的条件是此对象是否有必要执行finalize方法.

  • 当对象没有覆盖finalize方法,或者finalize方法已经被虚拟机调用过,虚拟机都将这两种情况视为没有必要执行
  • 当对象被判定为需要执行finalize方法,就把该对象放在F-Queue的队列中.并在稍后由一条由虚拟机自动建立的低优先级的finalize线程去执行.这是对象自我拯救的最后机会,在等待执行的过程中,如果成功连接上了gc链的某个对象,就可以逃出生天

垃圾回收算法

  • 标记清除法
    先标记,再清除.效率太低,碎片空间多
  • 复制算法
    内存分两块,每次只使用一半,一半用完,将活着的复制到 另一块上,再清理掉已使用的空间.
    代价大,实际可用内存只有一半.(Eden空间和survivor空间)
  • 标记整理算法
    前面和标记清除算法一样,后面是将标记的区域整理到同一端,而不是直接清除.
  • 分代收集算法
    将内存分成两块,新生代和老年代
    新生代:存活率低,使用复制孙发
    老年代:存活率高,使用标记整理/清除算法

垃圾收集器

是垃圾回收算法的具体实现.
没有最后好的垃圾搜集器,只有最合适的

  • serial
  • parnew 多线程版serial
  • serial old
  • parallel old
  • cms
  • G1 最新成果

内存分配和回收

  • 对象优先在eden空间分配
    当eden空间没有足够的空间分配的是,jvm发起Minor GC(新生代GC)
  • 大对象直接进入老年代
    避免出现死的快的大对象
  • 长期存活的对象进入老年代
    每次eden空间Gc的时候,都会给仍然存活的对象的年龄+1,当年龄增加到一定岁数的时候(默认15),会移入老年代
  • 空间分配担保
    每次进行minnr gc的时候,都会检测之前每次晋升到老年代的平均大小是否大于老年代的剩余空间大小.如果大于,就直接变成一次Full GC.

类加载机制

综述

类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,并对数据进行校验,转换解析和初始化,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。类的加载的最终产品是位于堆区中的Class对象,Class对象封装了类在方法区内的数据结构,并且向Java程序员提供了访问方法区内的数据结构的接口。

流程

  • 装载

    • 由ClassLoader及其子类负责.JVM在运行时会产生三个ClassLoader:根装载器(装载JRE的核心类库)、ExtClassLoader(扩展类装载器,装载JRE扩展目录ext中的JAR类包)和AppClassLoader(系统类装载器,Classpath路径下的类包)
    • 首先,通过一个类的全限定名来获取定义此类的二进制字节流(并没有指明要从一个Class文件中获取,可以从其他渠道,譬如:网络、动态生成、数据库等);
    • 其次,将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构;
    • 最后,在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口;
      加载阶段和连接阶段(Linking)的部分内容(如一部分字节码文件格式验证动作)是交叉进行的,加载阶段尚未完成,连接阶段可能已经开始
  • 链接

    • 校验
      检查字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。验证阶段是非常重要的,但不是必须的,它对程序运行期没有影响
    • 准备
      为静态变量分配空间,将变量初始化为默认值
    • 解析
      将常量池内的符号引用替换为直接引用的过程
  • 初始化
    到了初始化阶段,才真正开始执行类中定义的java程序代码。