《深入理解Java虚拟机》读书笔记

    最近两月系统的将《深入理解Java虚拟机》(周志明著 机械工业出版社  第二版)这本书看完了,虽然很多内容看的不要是很明白,但还是想写写读书笔记以总结下。

    1、概述

    这本书写还是挺好的,系统的介绍了虚拟机的各个方面,主要分为5个部分,走进java、自动内存管理机制、虚拟机执行子系统、程序编译与代码优化、高效并发。其中虚拟机执行子系统、程序编译与代码优化这两个部分主要讲述了类文件结构、虚拟机类加载机制、字节码执行引擎、编译期早期优化及编译期晚期优化;对于我(3年开发经验)来说这2部分有点难以理解,虽然看完,但是感觉没有理解。其他几部分算是基本理解了,理解的部分主要讲述:java内存区域与内存溢出异常、垃圾收集器与内存分配策略、虚拟机性能监控与故障处理工具、java内存模型与线程、线程安全与锁优化;以下我将我理解的这基本进行了个归纳总结,自己个做记录,也供大家参考和拍砖。

   2、走进java

    (1)java虚拟包括很多种,其中大家最熟悉的就是 Sun HotSpot VM了;

    (2)OpenJDK是一种开源的JDK,也是sun(后来oracle)公司整的,其性能、功能、执行逻辑与官方的oracle jdK差不多,大家可以学习下;不过大家要注意正式环境还是建议大家不要随机切换jdk版本和类型,上次我将服务器的jdk从1.6升级到JDK1.8部分代码执行就报错了。

   3、java内存区域与异常

    对于一名初学者,可能只是简单将java管理内存区域“简单”分为堆和栈,那么对一名中高级java工程师,这就不够了。在本书中,系统介绍了以下几个区域:

序号内存区域介绍抛出异常
1java堆最大的一块,存放对象实体,可分为新生代和老年代;线程共享的数据区outOfMemory
2java虚拟机栈储存局部变量表、操作数栈、动态链接、方法出口等信息;线程隔离的数据区stackOverFlowError(深度)
outOfMemoryError(内存大小)
3本地方法栈与java虚拟机栈类似,只不过虚拟机栈为虚拟机执行java方法服务、本地栈为native方法服务;
线程隔离的数据区
同上
4程序计数器当前程序所执行的字节码的行号指示器。线程隔离的数据区 
 方法区已被虚拟机加载的类信息、常量、静态变量、即时编译器后的代码;线程共享数据区outOfMemory
    

   4、垃圾收集器

    (1)哪些内存需要回收

     确定哪些对象还活着,主流用的方法是“可达性分析算法”,老的教科书可能说的“引用计数法”

    (2)什么时候回收、如何回收

       这跟用的垃圾收集算法、垃圾回收器是有很大关系的,jdk1.7update 14以后的虚拟机用的是G1垃圾回收器,主要用的基于标记-压缩算法。其他垃圾回收器包括CMS收集器、parNew收集器、Serial收集器;涉及算法主要包括标记-清除算法、复制算法、标记-整理算法。内容太多,需要的大家自己去看吧。

  5、内存分配与回收策略

     堆一般可分为新生代(eden)和老年代(old),回收一般分配为Minior GC和Full GC,Minior GC一般是在新生代堆中回收,Full GC在老年代回收,一般来说会触发Minior GC。Full GC 比Minior GC速度慢,频率低。随便说句,我发现稳定后的系统老年代的堆大小一般变化不大。

6、性能监控与故障处理工具

    在java的bin文件夹下,有个两个很好的可视化工具,一个是Jconsole和VisualVM工具,Jconsole轻量级一些,VisualVM功能全点,一般我是用Jconsole监控有问题后,再启用VisualVM监控,如有用问题,立马快照“堆 Dump”。

7、类文件

 .class文件可由java程序、JRuby程序、Groovy程序、其他语言生成,只要符合相应虚拟机规范就好了。

8、双亲委派加载机制

因为tomcat用的就是“双亲委派加载机制”,所以我特别注意了这种类加载机制,它主要工作过程:如果一个类加载器收到了类加载的请求,他首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动累加载器中,只有当父加载器反馈自己无法完成这个加载请求时,子加载器才会尝试自己去加载。

9、java内存

    java内存主要分为工作内存与主内存,工作内存可简单看成与“线程”一一对应,主内存存放着共享的数据。

10、线程安全的实现

笔者将这本书的线程安全这2章简单理解成一段话,供大家理解,深入学习还请自己照书系统学习。

线程安全实现可以由几下几种方法:

(1)synchronized

这种方法,大家都很熟悉,就是lock上某个变量、方法、程序段,在某个时刻,只允许一个线程访问lock上的数据。这个方法大家都很常用,但是笔者认为最大的两个弊端,一个弊端是效率低(据说jdk1.6以后有很大的改善),另一个弊端是等待的同优先线程获得解锁后的资源是随机的,并不按等待的先后顺序先后获得资源。

(2)java.util.concurrent包中的重入锁(ReentrantLock)

  对比synchronized,它有3个高级功能,一个是等待都可中断、二个是可实现公平锁、三个是锁可绑定多个条件。其中可实现公平锁是我最看重的,因为在并发量大的项目时,它比较合理。

(3)volatile

  volatile使用方法和synchronized差不多,主要是针对数据,它使用后有两个特性,一个是变量(数据)对所有线程都可见(包括更新后的变量(数据),但是在某些条件下不能及时能信); 二个是禁止指令重新优化排序。这个方法建议只有当大家深入理解后,才使用此方法。

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