JVM1 JVM内存模型1.1 类装载器ClassLoader1.2 程序计数器Program Counter Register1.3 虚拟机栈Java Virtual Machine Stacks1.4 本地方法栈Native Method Stacks1.5 方法区1.6 堆1.7 jvm参数2 对象创建2.1 给对象分配内存2.2 线程安全性问题2.3 初始化对象2.3.1 对象结构2.3.2 对象的访问定位3 垃圾回收3.1 如何判断对象为垃圾对象3.2 如何回收3.2.1 回收策略3.2.2 垃圾回收器4 class文件4.1 class文件简介4.1.1 类文件结构1 JVM内存模型1.1 类装载器ClassLoader负责加载class文件BootStrap启动类加载器C语言实现加载rt.jar里的所有class包括ObjectExtension扩展类加载器APPClassLoader应用程序类加载器也叫系统类加载器加载当前应用的classpath的所有类也可以自定义加载器只要继承ClassLoader就可以双亲委派机制委派给父类ClassLoader去加载为了保证原始的rt.jar下的代码不被篡改。AppClassLoader先不去加载委派给ExtClassLoader去加载ExtClassLoader也不去加载委派给BootStrap加载只有在父类加载不到的时候才会自己去加载。反射有几种方式三种。通过Object类的getClass方法来获取;使用.class的方式使用Class.forName方法native方法本地方法本地接口的作用是融合不同的编程语言为java所用1.2 程序计数器Program Counter Register是JVM中一块较小的内存区域保存着当前线程所执行的字节码的行号。如果正在执行的是native方法这个计数器的值为undefined。JVM的多线程是通过线程轮流切换并分配CPU执行时间片的方式来实现的任何一个时刻一个CPU都只会执行一条线程中的指令。为了保证线程切换后能恢复到正确的执行位置每条线程都需要有一个独立的程序计数器各线程间的程序计数器独立存储互不影响。此区域是唯一一个在java虚拟机规范中没有规定任何OutOfMemoryError情况的区域因为程序计数器是由虚拟机内部维护的不需要开发者进行操作。1.3 虚拟机栈Java Virtual Machine Stacks存放本地变量8中基本类型对象的引用变量实例方法)输入输出参数、方法中的变量栈操作记录入栈、出栈操作是线程隔离的每创建一个线程时就会对应创建一个Java栈即每个线程都有自己独立的虚拟机栈。栈帧包含局部变量表、操作数栈、动态链接、方法返回地址等信息每一个方法从调用到最终返回结果的过程就对应一个栈帧从入栈到出栈的过程。当前栈帧栈顶的栈帧才是有效的与这个栈帧相关联的方法称为当前方法当前活动帧栈始终是虚拟机栈的栈顶元素。局部变量表存放了编译期可知的各种基本数据类型和对象引用类型。通常我们所说的“栈内存”指的就是局部变量表这一部分。局部变量表所需的内存空间在编译期间完成分配当进入一个方法时这个方法需要在帧分配多少内存是固定的运行期间不会改变局部变量表的大小。64位的long和double类型的数据会占用2个局部变量空间其余的数据类型只占用1个。1.4 本地方法栈Native Method Stacks与虚拟机栈所发挥的作用是非常相似的其区别不过是虚拟机栈为虚拟机执行Java方法也就是字节码服务而本地方法栈则是为虚拟机使用到的Native方法服务。1.5 方法区存放类/接口信息常量静态变量运行时常量区是一种定义/接口一种规范。其中类信息包含包名、类名、继承的对象、接口定义、方法定义、类变量、类常量常量池 Constant Pool 是方法区的一部分 Class 文件除了有类的版本、字段、方法、接口等描述信息外还有一项信息就是常量池这部分内容将在类加载后进入方法区的运行时常量池中存放。永久带jdk7/元空间jdk8是方法区的实现。不会被垃圾回收关闭jvm时释放此区域所占内存。方法区溢出报错java.lang.OutOfMemoryError: PermGen space说明程序启动时需要加载大量第三方jar包例如在一个tomcat下不熟太多应用。可以增加该区域内存空间。Jdk1.6 及之前 有永久代 , 常量池 1.6 在方法区Jdk1.7 有永久代但已经逐步“去永久代”常量池 1.7 在堆Jdk1.8 及之后 无永久代常量池 1.8 在元空间1.6 堆类加载器读取了类文件后需要把类、方法、常变量放到堆内存中保存所有引用类型的真实信息。小对象内存分配先进栈上分配然后是eden区大对象直接进如老年代S0区线程区YoungGC只会回收eden1.7 jvm参数-Xms设置堆的最小空间大小。-Xmx设置堆的最大空间大小。-Xmn:设置年轻代大小-XX:NewSize设置新生代最小空间大小。-XX:MaxNewSize设置新生代最大空间大小。-XX:PermSize设置永久代最小空间大小。-XX:MaxPermSize设置永久代最大空间大小。-Xss设置每个线程的堆栈大小-XX:UseParallelGC:选择垃圾收集器为并行收集器。此配置仅对年轻代有效。即上述配置下,年轻代使用并发收集,而年老代仍旧使用串行收集。-XX:ParallelGCThreads20:配置并行收集器的线程数,即:同时多少个线程一起进行垃圾回收。此值最好配置与处理器数目相等。典型JVM参数配置参考:java-Xmx3550m-Xms3550m-Xmn2g-Xss128k-XX:ParallelGCThreads20-XX:UseConcMarkSweepGC-XX:UseParNewGC-Xmx3550m:设置JVM最大可用内存为3550M。-Xms3550m:设置JVM促使内存为3550m。此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。-Xmn2g:设置年轻代大小为2G。整个堆大小年轻代大小年老代大小持久代大小。持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,官方推荐配置为整个堆的3/8。-Xss128k:设置每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。更具应用的线程所需内存大 小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000 左右。2 对象创建2.1 给对象分配内存指针碰撞空间列表2.2 线程安全性问题线程同步性能较差同步开销本地线程分配缓冲TLAB2.3 初始化对象2.3.1 对象结构Header( 对象头自身运行时数据 Mark Word– 哈希值– GC 分代年龄– 锁状态标志– 线程持有锁– 偏向线程 ID– 偏向时间戳类型指针数组长度只有数组对象才有InstanceData相同宽度的数据分配到一起 long,doublePadding 对齐填充8 个字节的整数倍2.3.2 对象的访问定位使用句柄好处如果堆中的对象内存地址变更之后句柄的指向变更就可以了栈中对象的引用不需要改变缺点性能直接指针HotSpot3 垃圾回收3.1 如何判断对象为垃圾对象引用计数法、可达性分析引用计数法在对象中添加一个引用计数器当有地方引用这个对象的时候计数器 1 当失效的时候计数器 -1verbose:gc XX:PrintGCDetails可达性分析GCRoot 的对象虚拟机栈 局部变量表中的方法区的类属性所引用的对象方法区的常量所引用的对象本地方法栈所引用的对象3.2 如何回收3.2.1 回收策略标记清除、复制、标记整理、分代算法标记清除分成标记和清除两个阶段缺点效率问题、内存碎片复制缺点空间利用率低、只能用一般的空间堆新生代Eden、Survivor老年代Tenured Gen方法区虚拟机栈本地方法栈程序计数器4. 标记整理5. 分代算法3.2.2 垃圾回收器Serial、ParNew、CMS、G1、ZGC4 class文件public static void main(String args){ int a 2; int b 400; int c ab; System.out.println(c); 用javap命令反编译后public static void main(java.lang.String); descriptor: (Ljava/lang/String;)V //L代表引用类型 V代表没有返回值 flags: ACC_PUBLIC,ACC_STATIC //方法描述符 code: stack2,locals4,args_size1 //操作数栈深度为2本地变量表最大长度4(单位slot)参数1个 0: iconst_2 //常量2压栈 1: istore_1 //常量2出栈并保存到变量1里 2: iconst_3 //常量400压栈 3: istore_2 //常量400出栈并保存到变量2里接上4.1 class文件简介https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.htmlclass文件是一组已8位字符为基础单位的二进制流没有任何分隔符节省空间执行效率高。class文件只有两种数据类型无符号数、表4.1.1 类文件结构ClassFile { u4 magic; //魔数 u2 minor_version; //jdk版本号 8对应52 7对应51 类推 u2 major_version; //jdk版本号 u2 constant_pool_count; cp_info constant_pool[constant_pool_count-1]; u2 access_flags; u2 this_class; u2 super_class; u2 interfaces_count; u2 interfaces[interfaces_count]; u2 fields_count; field_info fields[fields_count]; u2 methods_count; method_info methods[methods_count]; u2 attributes_count; attribute_info attributes[attributes_count];}魔数代表了文件类型cafe babejava、grovy、jruby、scala都可以编译成class文件。这些语言只需要增加对应的编译器按照class规范翻译成class文件。