Matrix42 - jvm
type: channel
link: http://www.sundeqiang.cn/tag/jvm
items: 学习资料
items: 深入 JVM 内核—原理、诊断与优化之: 锁 (九)
items: 深入 JVM 内核—原理、诊断与优化之: Java堆分析 (八)
items: 深入 JVM 内核—原理、诊断与优化之: 类加载器 (六)
items: 深入JVM内核—原理、诊断与优化之:GC参数(五)
items: 深入JVM内核—原理、诊断与优化之:GC算法与种类(四)
items: 深入JVM内核—原理、诊断与优化之:常用JVM配置参数(三)
items: 深入JVM内核—原理、诊断与优化之:初识JVM(一)
items: JVM核心机制

学习资料
type: item
date: 2017-05-26T18:23:00+08:00
description: 常见数据结构与算法整理总结（上） 常见数据结构与算法整理总结（下） Java - 集合框架完全解析 关于Java集合的小抄 Java - 虚拟机学习笔记1 自动内存管理机制 Java - 虚拟机学习笔记2 类加载机制 Java - 网络编程完全总结 Java - 数据库学习笔记 Java - 设计模式学习总结 Java - 并发编程必知必会 如何理解面向对象思想 NIO 入门 Java动态性之:反射机制(Reflection) Java动态性之:动态编译(DynamicCompile) Java动态性之:脚本引擎执行javascript代码 JVM核心机制 JVM的栈上分配与逃逸分析 深入 JVM 内核—原理、诊断与优化之: GC 算法与种类 Hadoop框架基础（一） Hadoop框架基础（二） 关于数据科学的笔试和面试(BAT) hive优化总结 hadoop面试45题 java面试基础 多线程面试 红黑树 Hadoop深入面试问答题 hadoop面试原理性问题 Java内存模型深入讲解 《深入理解Java虚拟机》学习笔记（九）（Java内存模型与线程） 十种排序算法及其比较（java实现） Java内存模型与volatile关键字解析 Storm 性能优化 15道使用频率极高的基础算法题 二叉树相关算法题 链表相关算法题 经典算法题每日演练——第四题 最长公共子序列 经典算法专题 Java性能优化指南1.8版，及唯品会的实战 优秀博客 花钱的年华 骊骅 为梦码一生

深入 JVM 内核—原理、诊断与优化之: 锁 (九)
type: item
date: 2017-05-14T15:17:59+08:00
description: 线程安全 多线程网站统计访问人数 使用锁，维护计数器的串行访问与安全性 多线程访问ArrayList public static List<Integer> numberList =new ArrayList<Integer>(); public static class AddToList implements Runnable{ int startnum=0; public AddToList(int startnumber){ startnum=startnumber; } @Override public void run() { int count=0; while(count<1000000){ numberList.add(startnum); startnum+=2; count++; } } } public static void main(String[] args) throws InterruptedException { Thread t1=new Thread(new AddToList(0)); Thread t2=new Thread(new AddToList(1)); t1.start(); t2.start(); while(t1.isAlive() || t2.isAlive()){ Thread.sleep(1); } System.out.println(numberList.size()); } 在ArrayList进行扩容的时候处于不可用状态,这时进行操作会发生IndexOutOfBoundException 对象头Mark Mark Word，对象头的标记，32位 描述对象的hash、锁信息，垃圾回收标记，年龄 指向锁记录的指针 指向monitor的指针 GC标记 偏向锁线程ID 偏向锁 大部分情况是没有竞争的，所以可以通过偏向来提高性能 所谓的偏向，就是偏心，即锁会偏向于当前已经占有锁的线程 将对象头Mark的标记设置为偏向，并将线程ID写入对象头Mark 只要没有竞争，获得偏向锁的线程，在将来进入同步块，不需要做同步 当其他线程请求相同的锁时，偏向模式结束 -XX:+UseBiasedLocking 默认启用 在竞争激烈的场合，偏向锁会增加系统负担 public static List<Integer> numberList =new Vector<Integer>(); public static void main(String[] args) throws InterruptedException { long begin=System.currentTimeMillis(); int count=0; int startnum=0; while(count<10000000){ numberList.add(startnum); startnum+=2; count++; } long end=System.currentTimeMillis(); System.out.println(end-begin); } 本例中，使用偏向锁，可以获得5%以上的性能提升 -XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0 -XX:-UseBiasedLocking 轻量级锁 BasicObjectLock 嵌入在线程栈中的对象 普通的锁处理性能不够理想，轻量级锁是一种快速的锁定方法。 如果对象没有被锁定 将对象头的Mark指针保存到锁对象中 将对象头设置为指向锁的指针（在线程栈空间中） lock->set_displaced_header(mark); if (mark == (markOop) Atomic::cmpxchg_ptr(lock, obj()->mark_addr(), mark)) { TEVENT (slow_enter: release stacklock) ; return ; } lock位于线程栈中,判断一个线程是否持有轻量级锁，只要判断对象头的指针，是否在线程的栈空间范围内 如果轻量级锁失败，表示存在竞争，升级为重量级锁（常规锁） 在没有锁竞争的前提下，减少传统锁使用OS互斥量产生的性能损耗 在竞争激烈时，轻量级锁会多做很多额外操作，导致性能下降 自旋锁 当竞争存在时，如果线程可以很快获得锁，那么可以不在OS层挂起线程，让线程做几个空操作（自旋） JDK1.6中-XX:+UseSpinning开启 JDK1.7中，去掉此参数，改为内置实现 如果同步块很长，自旋失败，会降低系统性能 如果同步块很短，自旋成功，节省线程挂起切换时间，提升系统性能 偏向锁，轻量级锁，自旋锁总结 不是Java语言层…

深入 JVM 内核—原理、诊断与优化之: Java堆分析 (八)
type: item
date: 2017-05-07T23:30:00+08:00
description: 内存溢出(OOM)的原因 在JVM中，有哪些内存区间？ 堆,永久区,线程栈,直接内存 堆溢出 public static void main(String args[]){ ArrayList<byte[]> list=new ArrayList<byte[]>(); for(int i=0;i<1024;i++){ list.add(new byte[1024*1024]); } } 占用大量堆空间，直接溢出 Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at geym.jvm.ch8.oom.SimpleHeapOOM.main(SimpleHeapOOM.java:14) 解决方法：增大堆空间，及时释放内存 永久区 生成大量的类 public static void main(String[] args) { for(int i=0;i<100000;i++){ CglibBean bean = new CglibBean("geym.jvm.ch3.perm.bean"+i,new HashMap()); } } Caused by: java.lang.OutOfMemoryError: PermGen space [Full GC[Tenured: 2523K->2523K(10944K), 0.0125610 secs] 2523K->2523K(15936K), [Perm : 4095K->4095K(4096K)], 0.0125868 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] Heap def new generation total 4992K, used 89K [0x28280000, 0x287e0000, 0x2d7d0000) eden space 4480K, 2% used [0x28280000, 0x282966d0, 0x286e0000) from space 512K, 0% used [0x286e0000, 0x286e0000, 0x28760000) to space 512K, 0% used [0x28760000, 0x28760000, 0x287e0000) tenured generation total 10944K, used 2523K [0x2d7d0000, 0x2e280000, 0x38280000) the space 10944K, 23% used [0x2d7d0000, 0x2da46cf0, 0x2da46e00, 0x2e280000) compacting perm gen total 4096K, used 4095K [0x38280000, 0x38680000, 0x38680000) the space 4096K, 99% used [0x38280000, 0x3867fff0, 0x38680000, 0x38680000) ro space 10240K, 44% used [0x38680000, 0x38af73f0, 0x38af7400, 0x39080000) rw space 12288K, 52% used [0x39080000, 0x396cdd28, 0x396cde00, 0x39c80000) 解决方法：增大Perm区,允许Class回收 Java栈溢出 这里的栈溢出指，在创建线程的时候，需要为线程分配栈空间，这个栈空间是向操作系统请求的，如果操作系统无法给出足够的空间，就会抛出OOM public static class SleepThread implements Runnable{ public void run(){ try { Thread.sleep(10000000); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String args[]){ for(int i=0;i<1000;i++){ new Thread(new SleepThread(),"Thread"+i).start(); System.out.println("Thread"+i+" created"); } } -Xmx1g -Xss1m Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread 解决方法…

深入 JVM 内核—原理、诊断与优化之: 类加载器 (六)
type: item
date: 2017-04-30T23:08:36+08:00
description: class装载验证流程 加载 链接 验证 准备 解析 初始化 class装载验证流程 -加载 装载类的第一个阶段 取得类的二进制流 转为方法区数据结构 在Java堆中生成对应的java.lang.Class对象 class装载验证流程 -链接 验证 目的：保证Class流的格式是正确的 文件格式的验证 是否以0xCAFEBABE开头 版本号是否合理 元数据验证 是否有父类 继承了final类？ 非抽象类实现了所有的抽象方法 字节码验证 (很复杂) 运行检查 栈数据类型和操作码数据参数吻合 跳转指令指定到合理的位置 符号引用验证 常量池中描述类是否存在 访问的方法或字段是否存在且有足够的权限 class装载验证流程 -链接 准备 分配内存，并为类设置初始值 （方法区中） public static int v=1; 在准备阶段中，v会被设置为0 在初始化的中才会被设置为1 对于static final类型，在准备阶段就会被赋上正确的值 public static final int v=1; class装载验证流程 - 链接 解析 符号引用替换为直接引用 字符串引用对象不一定被加载 指针或者地址偏移量引用对象一定在内存 class装载验证流程 – 初始化 执行类构造器 static变量 赋值语句 static{}语句 子类的调用前保证父类的被调用 是线程安全的 Java.lang.NoSuchFieldError错误可能在什么阶段抛出? 什么是类装载器ClassLoader ClassLoader是一个抽象类 ClassLoader的实例将读入Java字节码将类装载到JVM中 ClassLoader可以定制，满足不同的字节码流获取方式 ClassLoader负责类装载过程中的加载阶段 JDK中ClassLoader默认设计模式 ClassLoader的重要方法 public Class<?> loadClass(String name) throws ClassNotFoundException 载入并返回一个Class protected final Class<?> defineClass(byte[] b, int off, int len) 定义一个类，不公开调用 protected Class<?> findClass(String name) throws ClassNotFoundException loadClass回调该方法，自定义ClassLoader的推荐做法 protected final Class<?> findLoadedClass(String name) 寻找已经加载的类 JDK中ClassLoader默认设计模式 – 分类 BootStrap ClassLoader （启动ClassLoader） Extension ClassLoader （扩展ClassLoader） App ClassLoader （应用ClassLoader/系统ClassLoader） Custom ClassLoader(自定义ClassLoader) 每个ClassLoader都有一个Parent作为父亲,启动ClassLoader除外 JDK中ClassLoader默认设计模式 – 协同工作 JDK中ClassLoader默认设计模式 public class HelloLoader { public void print(){ System.out.println("I am in apploader"); } } 放到D:/tmp/clz public class HelloLoader { public void print(){ System.out.println("I am in bootloader"); } } public class FindClassOrder { public static void main(String args[]){ HelloLoader loader=new HelloLoader(); loader.print(); } } 直接运行以上代码： I am in apploader 加上参数 -Xbootclasspath/a:D:/tmp/clz I am in bootloader 此时AppLoader中不会加载HelloLoader I am in apploader 在classpath中却没有加载 说明类加载是从上往下的 强制在apploader中加载 public static void main(String args[]) throws Exception { ClassLoader cl=FindClassOrder2.class.getC…

深入JVM内核—原理、诊断与优化之:GC参数(五)
type: item
date: 2017-04-10T18:09:27+08:00
description: 串行收集器 最古老，最稳定 效率高 可能会产生较长的停顿 -XX:+UseSerialGC 新生代、老年代使用串行回收 新生代复制算法 老年代标记-压缩 0.844: [GC 0.844: [DefNew: 17472K->2176K(19648K), 0.0188339 secs] 17472K->2375K(63360K), 0.0189186 secs] [Times: user=0.01 sys=0.00, real=0.02 secs] 老年代: 8.259: [Full GC 8.259: [Tenured: 43711K->40302K(43712K), 0.2960477 secs] 63350K->40302K(63360K), [Perm : 17836K->17836K(32768K)], 0.2961554 secs] [Times: user=0.28 sys=0.02, real=0.30 secs] 并行收集器 ParNew -XX:+UseParNewGC 新生代并行 老年代串行 Serial收集器新生代的并行版本 复制算法 多线程，需要多核支持 -XX:ParallelGCThreads 限制线程数量 多线程不一定快(看什么cpu),也会stop the world 0.834: [GC 0.834: [ParNew: 13184K->1600K(14784K), 0.0092203 secs] 13184K->1921K(63936K), 0.0093401 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] Parallel收集器 类似ParNew 新生代复制算法 老年代 标记-压缩 更加关注吞吐量 -XX:+UseParallelGC 使用Parallel收集器+ 老年代串行 -XX:+UseParallelOldGC 使用Parallel收集器+ 并行老年代 1.500: [Full GC [PSYoungGen: 2682K->0K(19136K)] [ParOldGen: 28035K->30437K(43712K)] 30717K->30437K(62848K) [PSPermGen: 10943K->10928K(32768K)], 0.2902791 secs] [Times: user=1.44 sys=0.03, real=0.30 secs] 并行收集器 -XX:MaxGCPauseMills 最大停顿时间，单位毫秒 GC尽力保证回收时间不超过设定值 -XX:GCTimeRatio 0-100的取值范围 垃圾收集时间占总时间的比 默认99，即最大允许1%时间做GC 这两个参数是矛盾的。因为停顿时间和吞吐量不可能同时调优 CMS收集器 Concurrent Mark Sweep 并发标记清除(与用户线程一起执行) 标记-清除算法 与标记-压缩相比 并发阶段会降低吞吐量 老年代收集器（新生代使用ParNew） -XX:+UseConcMarkSweepGC CMS运行过程比较复杂，着重实现了标记的过程，可分为 初始标记 根可以直接关联到的对象 速度快 并发标记（和用户线程一起） 主要标记过程，标记全部对象 重新标记 由于并发标记时，用户线程依然运行，因此在正式清理前，再做修正 并发清除（和用户线程一起） 基于标记结果，直接清理对象 1.662: [GC [1 CMS-initial-mark: 28122K(49152K)] 29959K(63936K), 0.0046877 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 1.666: [CMS-concurrent-mark-start] 1.699: [CMS-concurrent-mark: 0.033/0.033 secs] [Times: user=0.25 sys=0.00, real=0.03 secs] 1.699: [CMS-concurrent-preclean-start] 1.700: [CMS-concurrent-preclean: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 1.700: [GC[YG occupancy: 1837 K (14784 K)]1.700: [Rescan (parallel) , 0.0009330 secs]1.701: [weak refs processing, 0.0000180 secs] [1 CMS-remark: 28122K(49152K)] 29959K(63936…

深入JVM内核—原理、诊断与优化之:GC算法与种类(四)
type: item
date: 2017-03-13T21:41:00+08:00
description: GC的概念 Garbage Collection 垃圾收集 1960年 List 使用了GC Java中，GC的对象是堆空间和永久区 引用计数法 老牌垃圾回收算法 通过引用计算来回收垃圾 使用者 COM ActionScript3 Python 引用计数器的实现很简单，对于一个对象A,只要有任何一个对象引用了A,则A的引用计数器就加1，当引用失效时,引用计数器就减1.只要对象A的引用计数器的值为0,则对象A就不可能再被使用 引用计数法的问题 引用和去引用伴随加法和减法，影响性能 很难处理循环引用 标记-清除 标记-清除算法是现代垃圾回收算法的思想基础。标记-清除算法将垃圾回收分为两个阶段：标记阶段和清除阶段。一种可行的实现是，在标记阶段，首先通过根节点，标记所有从根节点开始的可达对象。因此，未被标记的对象就是未被引用的垃圾对象。然后，在清除阶段，清除所有未被标记的对象。 标记-压缩 标记-压缩算法适合用于存活对象较多的场合，如老年代。它在标记-清除算法的基础上做了一些优化。和标记-清除算法一样，标记-压缩算法也首先需要从根节点开始，对所有可达对象做一次标记。但之后，它并不简单的清理未标记的对象，而是将所有的存活对象压缩到内存的一端。之后，清理边界外所有的空间。 标记压缩对标记清除而言，有什么优势呢？ 复制算法 与标记-清除算法相比，复制算法是一种相对高效的回收方法 不适用于存活对象较多的场合 如老年代 将原有的内存空间分为两块，每次只使用其中一块，在垃圾回收时，将正在使用的内存中的存活对象复制到未使用的内存块中，之后，清除正在使用的内存块中的所有对象，交换两个内存的角色，完成垃圾回收 复制算法的最大问题是：空间浪费 整合标记清理思想 -XX:+PrintGCDetails的输出 Heap def new generation total 13824K, used 11223K [0x27e80000, 0x28d80000, 0x28d80000) eden space 12288K, 91% used [0x27e80000, 0x28975f20, 0x28a80000) from space 1536K, 0% used [0x28a80000, 0x28a80000, 0x28c00000) to space 1536K, 0% used [0x28c00000, 0x28c00000, 0x28d80000) tenured generation total 5120K, used 0K [0x28d80000, 0x29280000, 0x34680000) the space 5120K, 0% used [0x28d80000, 0x28d80000, 0x28d80200, 0x29280000) compacting perm gen total 12288K, used 142K [0x34680000, 0x35280000, 0x38680000) the space 12288K, 1% used [0x34680000, 0x346a3a90, 0x346a3c00, 0x35280000) ro space 10240K, 44% used [0x38680000, 0x38af73f0, 0x38af7400, 0x39080000) rw space 12288K, 52% used [0x39080000, 0x396cdd28, 0x396cde00, 0x39c80000) from 是两个小块的左面那个 to 是两个小块的右面那个 分代思想 依据对象的存活周期进行分类，短命对象归为新生代，长命对象归为老年代。 根据不同代的特点，选取合适的收集算法 少量对象存活，适合复制算法 大量对象存活，适合标记清理或者标记压缩 GC算法总结整理 引用计数 没有被Java采用 标记-清除 标记-压缩 复制算法 新生代 所有的算法，需要能够识别一个垃圾对象，因此需要给出一个可触及性的定义 可触及性 可触及的 从根节点可以触及到这个对象 可复活的 一旦所有引用被释放，就是可复活状态 因为在finalize()中可能复活该对象 不可触及的 在finalize()后，可能会进入不可触及状态 不可触及的对象不可能复活 可以回收 public class CanReliveObj { public static CanReliveObj obj; @Override protected void finalize() throws Throwable { super.finalize(); System.out.println("CanReliveObj finalize called"); obj = thi…

深入JVM内核—原理、诊断与优化之:常用JVM配置参数(三)
type: item
date: 2017-02-14T11:14:00+08:00
description: Trace跟踪参数 -verbose:gc -XX:+printGC 可以打印GC的简要信息 [GC 4790K->374K(15872K), 0.0001606 secs] [GC 4790K->374K(15872K), 0.0001474 secs] [GC 4790K->374K(15872K), 0.0001563 secs] [GC 4790K->374K(15872K), 0.0001682 secs] GC前使用的内存->GC后使用的内存 -XX:+PrintGCDetails 打印GC详细信息 -XX:+PrintGCTimeStamps 打印GC发生的时间戳 例 [GC[DefNew: 4416K->0K(4928K), 0.0001897 secs] 4790K->374K(15872K), 0.0002232 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] XX:+PrintGCDetails的输出(程序结束后打印堆的情况) Heap total = 12288K + 1536K ---------------------- 低边界(开始位置) 当前位置 最高边界(结束位置) def new generation total 13824K, used 11223K [0x27e80000, 0x28d80000, 0x28d80000)(新生代) eden space 12288K, 91% used [0x27e80000, 0x28975f20, 0x28a80000)(伊甸园) from space 1536K, 0% used [0x28a80000, 0x28a80000, 0x28c00000)(两个幸存代内存大小一样) to space 1536K, 0% used [0x28c00000, 0x28c00000, 0x28d80000) tenured generation total 5120K, used 0K [0x28d80000, 0x29280000, 0x34680000)(老年代) the space 5120K, 0% used [0x28d80000, 0x28d80000, 0x28d80200, 0x29280000) compacting perm gen total 12288K, used 142K [0x34680000, 0x35280000, 0x38680000)(永久区) the space 12288K, 1% used [0x34680000, 0x346a3a90, 0x346a3c00, 0x35280000) ro space 10240K, 44% used [0x38680000, 0x38af73f0, 0x38af7400, 0x39080000)(只读共享区,JDK 5.0之后有一个永久区的共享,基础类会被加载到共享区,供所有的JVM虚拟机使用) rw space 12288K, 52% used [0x39080000, 0x396cdd28, 0x396cde00, 0x39c80000)(可读可写的共享区) -Xloggc:log/gc.log 指定GC log的位置,以文件输出 帮助开发人员分析问题 -XX:+PrintHeapAtGC 每次GC前后,都打印堆信息 { Heap before GC invocations=0 (full 0): def new generation total 3072K, used 2752K [0x33c80000, 0x33fd0000, 0x33fd0000) eden space 2752K, 100% used [0x33c80000, 0x33f30000, 0x33f30000) from space 320K, 0% used [0x33f30000, 0x33f30000, 0x33f80000) to space 320K, 0% used [0x33f80000, 0x33f80000, 0x33fd0000) tenured generation total 6848K, used 0K [0x33fd0000, 0x34680000, 0x34680000) the space 6848K, 0% used [0x33fd0000, 0x33fd0000, 0x33fd0200, 0x34680000) compacting perm gen total 12288K, used 143K [0x34680000, 0x35280000, 0x38680000) the space 12288K, 1% us…

深入JVM内核—原理、诊断与优化之:初识JVM(一)
type: item
date: 2017-02-11T23:42:00+08:00
description: JVM概念 JVM是Java Virtual Machine的简称.意为Java虚拟机 虚拟机 指通过软件模拟的具有完整硬件系统功能的,运行在一个完全隔离环境中的完整计算机系统 有哪些虚拟机 VMWare Visual Box JVM VMWare或者Visual Box都是使用软件模拟物理CPU指令集 JVM使用软件模拟Java字节码的指令集 Java和JVM的历史 1996年SUN JDK 1.0 Classic VM 纯解释运行,使用外挂进行JIT 1997年 JDK 1.1 发布 AWT,内部类,JDBC,RMI,反射 1998年 JDK 1.2 Solaris Exact VM JIT 解释器混合 Accurate Memory Management 精确内存管理,数据类型敏感 提升了GC性能 JDK 1.2 开始成为Java2 J2SE J2EE J2ME出现 加入Swing Collections 2000年 JDK 1.3 Hotspot 作为默认虚拟机发布 加入JavaSound 2002年 JDK 1.4 Classic VM 退出历史舞台 Assert 正则表达式 NIO IPV6 日志API 加密类库 2004年发布 JDK1.5 即JDK5,J2SE 5,Java 5 泛型 注解 装箱 枚举 可变长的参数 Foreach循环 JDK1.6 JDK6 脚本语言支持 JDBC 4.0 Java编译器 API 2011年 JDK7发布 由于JDK7加入内容太多,项目规划出现问题直到2011年才发布,延误项目推出到JDK8 G1垃圾回收器 动态语言增强 64位系统中的压缩指针 NIO 2.0 2014年 JDK8 发布 Lambda表达式 Stream 语法增强 Java类型注解 2016年 JDK9 模块化 Java + REPL = jshell 简化进程API 轻量化JSON API 货币API 改善竞争锁 分割代码缓存区 Smart Java Compilation项目 大事记 使用最为广泛的JVM为HotSpot HotSpot为Longview Technologies开发 被SUN收购 2006年Java开源并建立OpenJDK HotSpot成为SUN JDK和Open JDK中所带的虚拟机 2008年Oracle收购BEA 得到JRockit VM 2010年Oracle收购SUN 得到Hotspot Oracle宣布在JDK8时整合JRockit和Hotspot,优势互补 在Hotspot基础上,移植JRockit优秀特性 各式JVM KVM Sun发布 IOS Android前,广泛用于手机系统 CDC/CLDC HotSpot 手机,电子书,Pad等电子设备上建立统一的Java编程接口 J2ME的重要组成部分 JRockit BEA IBM J9 VM IBM内部 Apache Harmony 兼容与JDK 1.5和JDK 1.6的Java程序运行平台 与Oracle关系恶劣 退出JCP Java社区的分裂 OpenJDK出现后,受到挑战,2011年退役 没有大规模商用经历 对Android的发展有积极作用 规范 Java语言规范 语法 变量 类型 文法 JVM规范 Class文件类型 运行时数据 帧栈 虚拟机的启动 虚拟机的指令集 Java语言规范 语法定义 IfThenStatement: if( Expression ) Statement ArgumentList: Argument ArgumentList,Argument 词法结构 \u + 4个16进制数字 表示UTF-16 行终结符:CR or LF,or CR LF 空白符 空格 tab \t 换页 \f 行终结符 注释 标识符(变量、类、方法等命名的符号) 关键字 int 0 2 0372 0xData_Cafe 1996 0x00_FF__00_FF 从JDK 1.7开始允许使用下划线分割数字 long 0l 0777L 0x1000000000L 2_17_483_68L 0xC0B0L float 1e1f 2.f .3f 0f 3.1444f 6.022137e+23f double 1e1 2. .3 0.0 3.14 1e-9d 1e137 操作 += -= *= /= &= |= ^= %= <<= >>= >>>= 类型和变量 元类型 byte short int long float char 变量初始化 boolean false char \u0000 泛型 JVM规范 Java语言规范定义了什么是Java语言 Java语言和JVM行对独立 Gloovy Clojure Scala JVM主要…

JVM核心机制
type: item
date: 2016-09-10T16:32:00+08:00
description: 1.类加载全过程 为什么研究类加载全过程 有助于了解JVM运行过程 更深入了解java动态性(热部署,动态加载),提高程序的灵活性 类加载机制 JVM把class文件加载到内存,并对数据进行校验,解析和初始化,最终形成JVM可以直接使用的java类型的全过程 加载-->链接(验证,准备,解析)-->初始化-->使用-->卸载 加载 将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区中运行时结构,在堆中生产一个代表这个类的java.lang.Class对象,作为方法区类数据的访问入口,这个过程需要类加载器参与 字节码可以是本地的也可以是从网络获取的,数据库获取的,等等 链接 验证 确保加载的类信息符合JVM规范,没有安全方面的问题 准备 正式为类变量(static变量)分配内存并设置类变量初始化的阶段,这些内存都将在方法区中进行分配(赋的是默认值,真正赋你定义的值在初始化阶段) 解析 虚拟机常量池内的符号引用替换为直接引用的过程(比如类名,方法名,变量名,类的代码,字符串常量等) 初始化 初始化阶段是执行类构造器\<clinit>()方法的过程,类构造器\<clinit>()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static块)中的语句合并产生的 当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先初始化其父类 虚拟机会保证一个类的\<clinit>()方法在多线程环境中被正确加锁和同步 当访问一个java类的静态域(变量)的时候,只有真正声明这个域的类才会被初始化 类的主动引用(一定会发生类的初始化) new一个类的对象 调用类的静态成员(除了final常量)和静态方法 使用java.lang.reflect包的方法对类进行反射调用 当虚拟机启动,一定会初始化main方法所在的类 当初始化一个类,如果其父类没有被初始化,则会先初始化它的父类 类的被动引用(不会发生类的初始化) 当访问一个静态域时,只有真正声明这个域的类才会被初始化 通过子类引用父类的静变量,不会导致子类初始化 通过数组定义类引用,不会触发此类的初始化 引用常量不会触发此类的初始化(常量在编译阶段存入调用类的常量池中了) Demo: public class Demo01{ public static void main(String[] args)throws Exception{ //主动引用 A a = new A(); System.out.println(A.width); Class.forName("A"); //被动调用 System.out.println(A.MAX); A[] as = new A[10]; System.out.println(B.width) } } class B extends A{ static{ System.out.println("静态初始化B类"); } } class A extends A_Father{ public static int width = 100; public static final int MAX = 100; static{ System.out.println("静态初始化A类"); width = 300; } public A(){ System.out.println("创建A类的对象"); } } class A_Father{ static{ System.out.println("静态初始化A_Father"); } } 2.类加载器作用 类加载器的作用 将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区中的运行时数据结构,在堆中生成一个代表这个类的java.lang.Class对象,作为方法区类数据的访问入口 类缓存 标准的Java SE类加载器可以按要求查找类,但一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间.不过JVM垃圾收集器可以回收这些Class对象 3.java.classClassLoader类介绍 作用 java.class.ClassLoader类的基本职责就是根据一个指定的类的名称,找到或者生产其对应的字节代码,然后从这些字节代码中定义出一个Java类,即java.lang.Class类的一个实例 除此之外ClassLoader还负责加载Java应用所需的资源,如图像文件和配置文件等 相关方法 getParent() 返回该类加载器的父类加载器 loadClass(String name) 加载名称为name的类,返回结果是java.lang.Class类的实例 findClass(String name) 查找名称为name的类,没找到则加载,返回的结果是jav…