深入理解Java虚拟机

php实现兼职网站 php实现兼职网站,包括用户的登录注册,以及企业用户等功能 立即下载

深入理解JVM

JVM 三大部分

  1. 类装载子系统
  2. 字节码执行引擎
  3. 运行时数据区(内存模型)

类加载过程

多个java文件经过编译打包成jar包,最终由java命令运行某个主类的main函数启动程序,这里首先需要通过类加载器把主类加载到JVM。
主类在运行过程中,如果使用到其他的类,会逐步加载这些类。
注意,jar包里的类(自己写的类)不是一次性全部加载,使用时才加载,可以通过指定参数 -verbose:class
A a = null; // 不会加载A,new的时候才加载

类加载步骤

  • 加载 -> 验证 -> 准备 -> 解析 -> 初始化 -> 使用 -> 卸载
  • 加载:将.class文件读入内存, 先加载main函数所在的主类,并不是同时加载所有的类,用到时才加载
  • 验证:验证字节码文件是否符合JVM规范
  • 准备:给类的静态变量(static)分配内存,并赋予默认值(如int = 0, obj = null)
  • 解析:将符合引用替换为直接引用,该阶段会把一些静态方法或私有方法(符号引用,比如main()方法)替换为指向数据所存内存的指针或句柄等(直接引用),这是所谓的静态链接过程(类加载期间完成),动态链接是程序运行期间完成的将符号引用转换为直接引用。
  • 初始化:对静态变量初始化为指定的值,并执行静态代码块
  • 卸载: 从内存中清除
  • Math.java/User.java… 编译打包 -> jar包 java Math.class main() -> 使用 User.class

类加载器和双亲委派机制

  • 启动类加载器:负责加载支撑JVM运行的位于JRE的lib目录下的核心类库(jre/lib下的jar包),如rt.jar,charsets.jar等
  • 扩展类加载器:负责加载支撑JVM运行的位于JRE的lib目录下的ext扩展目录中的jar包(jre/lib/ext下的jar包)
  • 应用程序类加载器:负责加载classpath路径下的类,主要是加载自己的class
  • 自定义加载器:
    • 继承ClassLoader
    • 重写findClass和loadClass方法
    • 负责加载用户自定义路径下的类包
  • defineClass: 验证 准备 解析 初始化

为什么设计双亲委派机制

  • 为了安全,防止核心API库被随意篡改
  • 为了避免重复加载,当父加载器已经加载了该类时,子加载器不用再次加载

打破双亲委派机制

  • tomcat下不同的war应用需要使用同一个第三方依赖库的不同版本时,无法通过双亲委派机制完成该需求
  • tomcat WebappClassLoader: 为了实现隔离性,没有遵循双亲委派机制,每个webappClassLoader加载自己目录下的class文件,不会传递给父加载器,打破了双亲委派机制
  • SPI机制也是打破双亲委派机制
  • 自己实现打破双亲委派机制的ClassLoader,需要重写loadClass方法,不通过父加载器加载
  • 自定义类加载器不能加载java开头的包,这是由Java的沙箱安全机制决定的,为了保证核心API不被恶意串改

Tomcat 类加载器

  • CommonClassLoader, 加载common目录下的jar包, Tomcat最基本的类加载器,加载路径中的class可以被Tomcat容器本身以及各个Webapp访问;
  • CatalinaClassLoader, 加载server/lib目录下的jar包,Tomcat容器私有的类加载器,加载路径中的class对于Webapp不可见
  • SharedClassLoader, 加载shared目录下的jar包,各个Webapp共享的类加载器,加载路径中的class对于所有的Webapp可见,但是对Tomcat容器本身不可见
  • WebappClassLoader, 各个Webapp私有的类加载器,加载路径中的class只对当前Webapp可见

JVM内存模型

在这里插入图片描述

1.堆:线程共享,在虚拟机启动时创建,是Java 虚拟机所管理的内存中最大的一块,主要用于存放对象实例,几乎所有的对象实例都在这里分配内存,注意Java 堆是垃圾收集器管理的主要区域,因此很多时候也被称做GC 堆,如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError 异常

堆中的java对象头中有一个指针,指向方法区中的该类的类元信息,及该类的类对象(Class对象)

  • 年轻代(默认1/3)
    • Eden(8/10): 新new出的对象通常在这里; Eden满的时候会触发一次GC,这个GC是minor GC(或者young GC),不是full GC
    • Survivor区:
      • From(1/10):
      • To(1/10):

    minor GC会回收Eden和Survivor中无引用的对象,是通过字节码执行引擎开启的垃圾收集线程来完成的

  • 老年代(默认2/3): 默认15次未被minor GC回收的对象会被挪到老年代,当老年代空间满的时候回触发full GC
    在这里插入图片描述
/**
 * 堆内存示例
 */
public class HeapTest {
    byte[] a = new byte[1024*100]; //100 kb

    public static void main(String[] args) throws Exception {
        List heapTestList = new ArrayList();
        while (true) {
            heapTestList.add(new HeapTest());
            Thread.sleep(30);
        }
    }
}

在这里插入图片描述
注意上图中黑色矩形圈出的部分:

  • 可以看到,当Eden满的时候会触发minor GC, 触发minor GC时,Eden区域会清空,Survivor0和Survivor1会交替的清空和填充,Old区域会随着每次minor GC而增加对象(minor GC 15次未清理的对象)
  • 当老年代被充满后会触发full GC
  • 当full GC无法回收空间后,程序抛出OOM异常:Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

堆内存相关参数:

  • -Xms:堆内存初始大小
  • -Xmx:堆内存最大值
  • -Xmn: 新生代大小

2.方法区(元空间):线程共享,又称Non-Heap: 主要用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据,根据Java 虚拟机规范的规定,当方法区无法满足内存分配需求时,将抛出OutOfMemoryError 异常。值得注意的是在方法区中存在一个叫运行时常量池(Runtime Constant Pool)的区域,它主要用于存放编译器生成的各种字面量和符号引用,这些内容将在类加载后存放到运行时常量池中,以便后续使用。

  • 静态变量,常量等引用存放在方法区,该引用也是一个指针,指向堆内存中实际的对象
  • -XX:MetaspaceSize
  • -XX:MaxMetaspaceSize

3.程序计数器: 线程私有,属于线程私有的数据区域,是一小块内存空间,主要代表当前线程所执行的字节码行号指示器。字节码执行引擎工作时,通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。

4.虚拟机栈: 线程私有,与线程同时创建,总数与线程关联,代表Java方法执行的内存模型。每个方法执行时都会创建一个栈桢来存储方法的的变量表(局部变量)、操作数栈、动态链接方法、返回值、返回地址等信息。每个方法从调用到结束就对于一个栈桢在虚拟机栈中的入栈和出栈过程

栈帧: 一个方法对应一块栈帧内存区域,栈帧中包含以下内容:

  • 局部变量表
  • 操作数栈
  • 动态链接
  • 方法出口
/**
 * 栈内存溢出示例
 * 设置栈内存大小:-Xss160k, 每一个线程的栈内存大小;
 */
public class StackOverflowTest {

    static int count = 0;

    public static void redo() {
        count ++;
        redo();
    }

    public static void main(String[] args) {
        try {
            redo();
        } catch (Throwable t) {
            t.printStackTrace();
            System.out.println("count:" + count);
        }
    }
}

运行结果:
java.lang.StackOverflowError
	at com.guoweizu.demo.tuling.StackOverflowTest.redo(StackOverflowTest.java:12)
	at com.guoweizu.demo.tuling.StackOverflowTest.redo(StackOverflowTest.java:13)
	at com.guoweizu.demo.tuling.StackOverflowTest.redo(StackOverflowTest.java:13)
	...
count:22422

虚拟机栈中有存放了对象的引用以及基本类型的值,这个对象引用是一个内存地址,指向堆内存中实际的对象

参数: -Xss1m(默认), -Xss160k(jdk1.8.111版本的最小栈空间)

5.本地方法栈: 线程私有,这部分主要与虚拟机用到的 Native 方法相关,一般情况下,我们无需关心此区域。

JVM参数调优

  1. 根据自己的系统估算每秒大概会产生多少对象,根据这些对象的特性判断这些对象会存放在堆中的哪个区域,以及在这些区域大概会存留多久,然后在针对不同的内存区域设置适当的参数
  2. 根据对象特性选择适当的垃圾回收器
  3. 垃圾对象尽量在年轻代就被minor GC回收,避免被挪到老年代,减少full GC次数

逃逸分析

JVM运行的三种模式:

  • 解释模式(Interpreted Mode): 只使用解释器(-Xint 强制JVM使用解释器模式),执行一行JVM字节码就编译一行为机器码
  • 编译模式(Compiled Mode): 只使用编译器(-Xcomp 强制JVM使用编译模式),先将所有JVM字节码一次编译为机器码,然后一次性执行所有机器码
  • 混合模式(Mixed Mode): 依然使用解释模式执行代码,但是对于一些"热点"代码采用编译模式执行,JVM一般采用混合模式执行代码

解释模式启动快,对于只需要执行部分代码,且大多数代码只会执行一次的情况比较适合;编译模式启动慢,但是后期执行快,而且比较占用内存,因为机器码的数量至少是JVM字节码的10倍以上,这种模式适合代码可能被反复执行的场景;混合模式JVM默认的执行方式,一开始还是解释执行,但是对于少部分"热点"代码会裁员编译模式执行,这些热点代码对应的机器码会被缓存起来,下次执行无需再编译,这就是我们常见的JIT(Just In Time Compiler)即使编译技术。

  • 对象逃逸分析:

逃逸分析:JVM在即时编译时判断方法中变量是否只保留在本方法内部,不会逃逸出方法外,例如,局部变量没有被return;如果只保留在方法内部,对象就可以分配在栈内存的栈帧中,随着方法执行结束被回收,不用分配到堆上,减少GC
-XX:+DoEscapeAnalysis(打开逃逸分析); JDK7以后默认打开
-XX:-DoEscapeAnalysis(关闭逃逸分析)

JVM垃圾回收

  • Minor GC/Young GC: 收集新生代的垃圾对象,minor GC非常频繁,回收速度一般也比较快
  • Major GC/Full GC: 收集老年代,年轻代和方法区的垃圾,Full GC的垃圾回收速度一般比Minor GC慢10倍以上。
/**
 * 垃圾回收示例
 * 打印垃圾回收信息参数: -XX:+PrintGCDetails
 * 打印GC日志: -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:./gc.log
 */
public class GCTest {
    public static void main(String[] args) {
        byte[] allocation1new = new byte[1024 * 60000];
    }
}

运行结果:
Heap
 PSYoungGen      total 76288K, used 65246K [0x000000076ab00000, 0x0000000770000000, 0x00000007c0000000)
  eden space 65536K, 99% used [0x000000076ab00000,0x000000076eab7bc0,0x000000076eb00000)
  from space 10752K, 0% used [0x000000076f580000,0x000000076f580000,0x0000000770000000)
  to   space 10752K, 0% used [0x000000076eb00000,0x000000076eb00000,0x000000076f580000)
 ParOldGen       total 175104K, used 0K [0x00000006c0000000, 0x00000006cab00000, 0x000000076ab00000)
  object space 175104K, 0% used [0x00000006c0000000,0x00000006c0000000,0x00000006cab00000)
 Metaspace       used 3308K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 365K, capacity 388K, committed 512K, reserved 1048576K

进入老年代的情况:

  1. 大对象会直接被放入老年代
    • -XX:PretenureSizeThreshold=1000000 -XX:+UserSerialGC 设置大对象的大小为1M,单位为字节,超过1m的会直接放入老年代
    • 为了避免大对象在minor GC时再From和To之间不停挪动
  2. 长期存活的对象将进入老年代(默认15岁)
    • -XX:MaxTenuringThreshold=5 设置年龄
  3. 对象动态年龄判断:执行minor GC时,JVM会判断survivor区中的对象:将所有对象根据年龄大小,从小到大相加,当加到n时已经超过了survivor区(一块survivor区:s0或者s1)的50%,则将n及n以上年龄的对象全部直接挪到老年代;
    • 比如:survivor区总共为200m(s0和s1分别为200m), 将所有对象按年龄排序相加: 1+2+…+n, 例如加到n=10时,总大小超过了100m,那么将10及10以上年龄的对象全部挪到老年代
  4. minor GC时,Survivor区放不下的对象会被直接放入老年代
  5. 老年代空间分配担保机制: 触发minor GC之前,JVM会执行以下逻辑,来保证老年代有足够的空间:
    • 老年代剩余可用空间 < 年轻代里现有的所有对象所占空间: 如果是,则继续执行下一个判断,否则直接执行minor GC
    • 是否配置 -XX:-HandlePromotionFailure(1.8已默认配置);没配置,直接Full GC, 否则执行下一个判断
    • 老年代剩余可用空间 < 每次minor GC后进入老年代的对象的平均大小, 如果为真,则执行Full GC, 否则执行minor GC
      在这里插入图片描述

如何判断对象可以被回收

  1. 引用计数器: 对象每被引用一次(赋值一次)计数器加1,当引用失效,计数器减1,当计数器为0时,则可回收
    • 相互引用问题,目前JDK不使用这种方式
  2. 可达性分析:基本思想就是通过一系列的称为"GC Roots"的对象作为起点, 从这些节点开始向下搜索,找到的对象都标记为非垃圾对象,其他对象都是垃圾对象;
    • 常用的GC Roots根节点: 线程栈的本地变量,静态变量,本地方法栈的变量等
    • 目前JDK默认使用方式
  3. 常见引用类型, java的4种引用类型:
    • 强引用:普通的变量引用
      User user = new User();
      
    • 软引用:当GC做完后发现释放不出空间存放新对象,则会把这些软引用的对象回收掉
      SoftReference<User> user = new SoftReference<User>(new User());
      
      可用来实现内存敏感的高速缓存
    • 弱引用:WeakReference, GC会直接回收
    • 虚引用:几乎不用
  4. finalize()方法最终判定对象是否存活
    1. 第一次标记并进行一次筛选; 判断是否覆盖了finalize()方法
    2. 第二次标记
  5. 如果判断一个类是无用的类, 方法区主要回收无用的类,判断一个类是无用的类的条件:
    • 该类所有的实例都已被回收,也就是Java堆中没有该类的实例
    • 加载该类的ClassLoader已经被回收
    • 该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。

垃圾回收算法

  1. 标记-清除算法
    • 效率问题
    • 空间问题(会产生大量不连续的碎片)
  2. 复制算法
    • 将内存分为两块,一部分是使用区,一部分是保留区,收集时将不能回收的对象复制到保留区(连续存放),然后将剩下的全部清理掉
    • 空间利用率低
  3. 标记整理算法
  4. 分代收集算法,年轻代用一种算法,老年代用一种算法

垃圾收集器

  1. Serial收集器
    • -XX:+UseSerialGC (新生代:复制算法)
    • -XX:+UseSerialOldGC (老年代:复制整理算法)
    • 历史最悠久的垃圾收集器。单线程的收集器, 执行垃圾收集时,停止所有用户线程,只执行垃圾收集线程
  2. ParNew收集器
    • -XX:+UseParNewGC:SerialGC的多线程版本,
    • 收集时停止所有的用户线程,只执行垃圾收集线程,适用于多核的处理器,默认的收集线程数跟cpu核数相同;
    • 目前用得较多的垃圾收集器。通常和CMS搭配使用
  3. Parallel Scavenge收集器
    • -XX:+UseParallelGC(年轻代:复制算法),
    • -XX:+UseParallelOldGC(老年代:标记整理算法):
    • 类似于ParNew收集器,是server模式下的默认收集器(内存大于2G, CPU大于2)
    • 可以设置STW的时间,但是如果时间不够就不一定能将堆中的垃圾收集干净,未收集的下次再回收
  4. CMS收集器(Concurrent Mark Sweep)
    • 只能用在老年代
    • 标记清除算法,
    • -XX:+UseConcMarkSweepGC
    • 是一种以获取最短停顿时间为目标的收集器, STW时间尽量短
    • HotSpot虚拟机第一款真正意义上的并发收集器,他第一次实现了让垃圾收集线程与用户线程(基本上)同时工作
    • 收集过程分为以下4个阶段:
      1. 初始标记:暂停所有的其他线程,并记录下gc roots直接能引用的对象(不会深入遍历,因此速度很快,深入遍历会在并发标记阶段),该阶段会STW, 但速度很快;
      2. 并发标记:GC线程与用户线程同时执行,用一个闭包结构记录可达对象。但在这个阶段结束,这个闭包结构并不能保证包含当前所有的可达对象。因为用户线程在这个阶段可能更新引用域,所以GC线程无法保证可达性分析的实时性,这个阶段会记录发生引用更新的地方,用于下一个阶段重新标记;
      3. 重新标记:重新标记阶段就是为了修正并发标记期间因为用户线程继续运行而导致标记产生变动的那一部分对象的标记记录,这个阶段也会STW, 停顿时间一般比初始标记阶段稍长,但远远小于并发标记阶段的时间
      4. 并发清理:开启用户线程,同时GC线程开始对未标记的区域做清理;
    • 缺点:
      • 对CPU资源敏感
      • 无法收集浮动垃圾(GC过程中产生的垃圾,在下一次GC时收集)
      • 标记清除算法,会产生内存碎片:通过设置-XX:UseCMSCompactAtFullCollection参数,可以让JVM执行完GC后做整理
      • 当CMS gc还未完成时,由于应用程序继续运行可能再次触发GC, 这时会出现"concurrent mode failure",此时会进入stop the world, 然后改用serial old垃圾收集器来回收
    • CMS相关参数:
      • -XX:+UseConcMarkSweepGC: 启用CMS
      • -XX:ConcGCThreads: 并发的GC线程数
      • -XX:+UseCMSCompactAtFullCollection: full GC后做压缩整理
      • -XX:CMSFullGCsBeforeCompaction: 多少次full GC后做压缩整理,默认为0, 每次完成都后整理(必须要设置-XX:+UseCMSCompactAtFullCollection参数后才生效)
      • -XX:CMSInitiatingOccupancyFraction: 当老年代使用达到该比例时会触发Full GC(默认是92, 这是百分比)
      • -XX:+UseCMSInitiatingOccupancyOnly: 只使用设定的回收阈值(-XX:CMSInitiatingOccupancyFraction设定的值),如果不指定,JVM仅在第一次使用设定值,后续则会自动调整
      • -XX:+CMSScavengeBeforeRemark: 在CMS GC前启动一次minor GC, 目的在于减少老年代对年轻代的引用,降低CMS GC的标记阶段的开销,一般CMS的GC耗时80%都在标记阶段
  5. G1收集器:
    • -XX:+UseG1GC
    • 是一款面向服务器的垃圾收集器,主要针对配置了多颗处理器及大容量内存的机器,以及高概率满足GC停顿时间要求的同时,还具备高吞吐量性能特征。
    • 将Java堆划分为大小相等的独立区域(region), 最多可划分2048个region; 在这里插入图片描述
    • 每个region的大小就是总的堆内存/2048;例如堆大小4096m,那每个region为4096/2048=2m
    • 可通过-XX:G1HeapRegionSize设置region的大小
    • G1保留了年轻代和老年代的概念,但是不再物理隔离,他们都是region的集合(可以不连续)
    • 默认的年轻代占5%,例如堆内存4096m, 那么年轻代大约200m,对应大概100个region

      当年轻代满的时候,G1会在触发Young GC之前会比较本次收集的时间与设置的停顿时间,如果远远小于设置的时间,那么G1会增加年轻代的region

    • 可以通过-XX:G1NewSizePercent设置新生代初始占比,在系统运行中,JVM会不停给年轻代增加更多的region,但是最大不会超过60%,最大占比可以通过-XX:G1MaxNewSizePercent参数修改。
    • 年轻代中的eden和survivor区的比例和之前一样,也是8:1:1
    • 一个region可能之前是年轻代,但是region经过垃圾回收后,可能变为老年代,也就是说Region的区域功能可能动态变化。
    • G1垃圾收集器对于对象什么时候进入老年代的原则和之前一样,唯一不同的是对大对象的处理,G1有专门分配大对象的region叫Humongous区,而不是让大对象直接进入老年代Region区
    • G1对大对象的判定规则:一个对象的大小超过了一个Region大小的50%,比如之前Region大小为2m,那么超过1M的对象会被当做大对象放入Humongous区,而且如果一个对象太多,可能横跨多个连续的region来存放。
    • Humongous区专门存放短期巨型对象,不用直接放入老年代,可以节约老年代的空间,避免因老年代空间不够的GC开销
    • Full GC的时候处理收集年轻代和老年代之外,也会将Humongous区一并回收。
    • G1垃圾收集过程:
      1. 初始标记(Initial Mark, STW): 暂停所有其他线程,并记录下gc roots能直接引用的对象,速度很快
      2. 并发标记(Concurrent Mark): 同CMS的并发标记
      3. 最终标记(Remark, STW): 同CMS的重新标记
      4. 筛选回收(Cleanup, STW): 筛选回收阶段首先对各个region的回收价值和成本进行排序,根据用户所期望的GC停顿时间(可通过-XX:MaxGCPauseMillis指定)来制定回收计划

        比如有1000个region需要回收,但是回收需要200毫秒,如果用户指定的停顿时间为100毫秒,那么G1会通过之前的回收成本计算,可能只能收集800个region,那么本次就只会回收800个region

    • 回收算法用的是复制算法,不会产生太多的内存碎片
    • G1收集器在后台维护了一个优先列表,每次根据允许的收集时间,优先选择回收价值大最大的region(这也就是它的名字Garbage First的由来)

      比如一个region花200毫秒能回收10m垃圾,另一个region花50毫秒可以回收20m垃圾,在回收时间有限的情况下,那么G1会优先回收后一个region

    • 常用参数汇总:
      • -XX:+UseG1GC:启用G1垃圾回收器
      • -XX:ParallelGCThreads: 垃圾回收开启的线程数
      • -XX:MaxGCPauseMillis: 目标暂停时间(默认200ms)
      • -XX:G1NewSizePercent: 新生代内存初始空间(默认整堆的5%)
      • -XX:G1MaxNewSizePercent: 新生代内存最大空间
      • -XX:TargetSurvivorRatio: Survivor区的填充容量(默认50%),Survivor区域里的一批对象(年龄1+年龄2+…+年龄n的所有对象)总和超过了Survivor区的50%,此时会把年龄为n及以上的对象都放入老年代的region中
      • -XX:MaxTenuringThreshold: 判定进入老年代的年龄阈值(默认15)
      • -XX:InitiatingHeapOccupancyPercent: 老年代占用空间达到整个堆内存阈值(默认45%),则执行Mixed GC,比如有2048个region,当有接近1000个region被老年代对象占用时,就会触发Mixed GC
      • -XX:G1HeapWastePercent:默认5%,gc过程中空出来的region是否充足阈值,在Mixed GC时,对Region回收都是基于复制算法进行的,都是把要回收的Region里的存活对象复制到其他region,然后这个region的垃圾对象全部清理掉,这样的话在回收过程就会不断空出来新的region,一旦空闲出来的region数量达到了堆内存的5%,此时就会立即停止Mixed GC,意味着本次GC结束
      • -XX:G1MixedGCLiveThresholdPercent:默认85%,region中的存活对象低于这个值时才回收该region,如果超过这个值,存活对象过多,回收的意义不大。
      • -XX:G1MixedGCCountTarget: 在一次Mixed GC回收过程中指定做几次筛选回收(默认8次),在筛选回收阶段,可以回收一会,然后暂停回收,恢复系统运行,一会再回收,这样可以让系统不至于单次停顿时间过长
    • G1的垃圾收集分类:
      • Young GC: 当年轻代满的时候,G1会在触发Young GC之前会比较本次收集的时间与设置的停顿时间,如果远远小于设置的时间,那么G1会增加年轻代的region,否则就执行Young GC
      • Mixed GC: 不是full GC, 老年代的空间占有率达到参数(-XX:InitiatingHeapOccupancyPercent)设定的值时触发,回收所有的Young和部分old(根据期望的GC停顿时间确定old区回收多少,G1维护了region回收的顺序列表)以及大对象区,正常情况G1的垃圾回收是先做MixedGC,主要使用复制算法,需要把各个region中存活的对象拷贝到别的region中去,拷贝过程中如果发现没有足够的空region来承载需要拷贝的对象就会触发Full GC.
      • Full GC: 停止所有用户线程,然后采用单线程进行标记、清理和压缩整理,好空闲出来一批region供下次Mixed GC使用,这个过程非常耗时(类似CMS发生"concurrency mode failure"后使用Serial GC一样)
    • 使用G1的场景
      • 50%以上的堆被存活对象占用
      • 对象分配和晋升的速度变化非常大
      • 垃圾回收时间特别长,比如超过1秒
      • 8GB以上的对内存(推荐值)
      • 停顿时间需要控制在500ms以内

JVM工具使用

  1. jmap: 查看内存信息,包括实例个数及占用内存大小
    $ jmap -histo $pid # 查看实例数以及占用内存
    $ jmap -heap $pid # 查看堆内存情况
    $ jmap -dump:format=b,file=myapp.hprof $pid # 导出内存快照
    
  2. jstack: 查看死锁
  3. jinfo: 查看jvm参数
  4. jstat: 最重要的工具,查看内存及gc情况
    $ jstat -gc $pid
    # 每隔1000毫秒打印一次,总共打印5次, 可以根据频率来计算对象的增长速率,以及观察内存的使用情况
    $ jstat -gc $pid 1000 5
    
  5. jvisualvm:可视化工具

GC日志

  1. 打印GC日志参数:
    -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:./gc.log
    
  2. GCeasy

常量池

  • 字面量
    • 类的全额限定名和描述符
    • 方法的全额限定名和描述符
    • 变量的名称和描述符
  • 常量池
B站DRM视频解密流程实战解析:从密钥获取到播放全流程 本文详细解析了B站DRM视频的解密全流程,从识别加密视频、捕获关键网络请求(如playurl接口的widevine_pssh数据),到逆向分析DRM SDK的JavaScript执行逻辑,最终手动模拟EME流程获取解密密钥,并使用mp4decrypt和ffmpeg工具完成视频文件的解密与合并。文章为开发者提供了从密钥获取到播放的完整实战指南。 阅读详情

相关推荐

华为昇腾Atlas200DK. CANN模型推理——目标检测结果不对(无检测结果)的问题解决

目录前言问题描述问题排查1.后处理模块问题排查2.预处理模块问题排查3.模型问题排查4.算法bug问题排查5.AI板卡问题排查6.模型精度问题排查6.模型推理问题解决:模型输入数据与预处理不同后记 前言 上周我在华为昇腾Atlas200DK中部署nanodet和yolov5时,出现了目标检测结果不对(没有检测到任何物体),困扰了整整三天,最后找到原因并圆满解决,在这里记录一下debug过程。 以上测试均在python中完成。 问题描述 第一天上午,我首先将nanodet由pytorch的.pth模型转换为.

qq_41035283的博客 5604

-XX:PretenureSizeThreshold的默认值和作用浅析

一、背景 《深入理解Java虚拟机》第93页,3.6.2 大对象直接进入老年代。 讲到大对象主要指字符串和数组,虚拟机提供了一个-XX:PretenureSizeThreshold参数,大于这个值的参数直接在老年代分配。 这样做的目的是避免在Eden区和两个Survivor区之间发生大量的内存复制(新生代采用复制算法)。 但是这里没讲清楚默认值是多少,默认会不会“大”对象直接进入老年代。 ...

悟鸣的技术博客 2万+

OTN设备核心知识速记

本文章为工作笔记,若有错误,还需大家指正。不定期更新。

Hiddengold的博客 2648

接低预算私活做电商平台! 我为啥选纯PHP+MySQL?

最近接了个私活,甲方爸爸说要搞个电商平台,预算嘛...反正够买几杯奶茶的。作为一个资深的PHP手艺人,我决定自己撸一个,毕竟现成的系统要么太臃肿,要么收费贵得离谱。下面记录下这个作死的过程,顺便分享点干货。先说说技术选型。Laravel?太重量级了。ThinkPHP?文档写得跟天书似的。

ZLNuTPTW的博客 1294

深入解析AMBA5 AXI与ACE协议:从基础到高级应用

本文深入解析了AMBA5 AXI与ACE协议的核心机制与应用。AXI协议通过分离通道、突发传输和乱序完成实现高性能数据传输,而ACE协议在此基础上构建了硬件级缓存一致性解决方案,通过监听机制和状态模型确保多核系统数据统一。文章还探讨了在异构计算等复杂场景下的实战应用与AMBA5的新特性。

cc789的博客 961

利用GBD数据库做未来疾病负担预测

最近看到一篇文献,利用GBD数据库中的数据对疾病负担的发展趋势进行预测。觉得很有趣,就抽空用R语言复盘了一下里面关键的方法。 参考文献: Changing trends in the disease burden of esophageal cancer in China from 1990 to 2017 and its predicted level in 25 years DOI: 10.1002/cam4.3775 1. 相关R包的安装 主要用到的R包有3个,一个一个讲: 1.1 Nordpred

NickyCat的博客 5万+

php哪里接私活_php程序员怎么接私活

随着php7的发布,php这一计算机语言又一次出现了质的突破。那么,作为php程序员,怎么做才能有更大的发展呢?答案当然是不断钻研技术。那么然后呢?优秀的技术要是不能转化为人民币,似乎也有些偏颇,所以我们需要将技术再做转化。那么,除了正常php程序员的工作外,一个php高手还能通过做哪些工作挣外快呢?今天和大家分享一下自己的经验吧。1.做几个网站,通过百度联盟或者其他联盟挣外快。百度联盟现在的手机...

weixin_29442031的博客 781

基于STM32与毫米波雷达的非接触式睡眠监测系统

物联网和嵌入式系统技术正在推动医疗健康设备的智能化发展。通过传感器网络采集生理信号,结合信号处理算法实现健康监测已成为主流技术方案。毫米波雷达凭借其非接触检测特性,在呼吸、心率等生命体征监测中展现出独特优势。STM32系列MCU凭借丰富外设和低功耗特性,成为医疗级嵌入式设备的首选平台。本系统整合60GHz毫米波雷达、红外测温与无线传输模块,构建了完整的睡眠质量评估解决方案,其硬件架构设计、信号处理算法和低功耗优化策略对可穿戴医疗设备开发具有参考价值。

weixin_36369848的博客 612

java类加载机制解析

java类加载机制、双亲委派机制

qq_35314762的博客 1035

RK3568 MIPI屏幕启动异常:从uboot logo到黑屏的排查与修复

本文详细分析了RK3568平台MIPI屏幕在启动过程中,从uboot阶段正常显示logo到内核阶段黑屏的典型故障。通过硬件测量与软件调试,最终定位问题根源在于电源时序,并提供了在设备树中为屏幕供电的regulator节点添加`regulator-boot-on`属性的关键解决方案,有效解决了因内核启动早期电源管理导致的显示异常。

weixin_29161719的博客 541

《Python星球日记》 第72天:问答系统与信息检索

《Python星球日记》 第72天:问答系统与信息检索,在前面的日子里,我们学习了自然语言处理的基础知识,包括文本预处理、词向量、Transformer架构和各种预训练模型。今天,我们将探索问答系统这一NLP的重要应用,以及如何结合信息检索技术构建智能问答系统。

Code_流苏:在代码中寻诗意,在实践中觅真知 1075

Python与PHP:哪个更适合接私活?

根据这个论据,从项目需求的角度来看,如果项目涉及到数据分析、机器学习等领域,那么Python无疑是更好的选择。如果你对数据分析、机器学习等领域感兴趣,并且已经掌握了Python的相关技能,那么Python可能是你的首选。如果你对Web开发有浓厚的兴趣,并且已经熟练掌握了PHP的相关技能,那么PHP将更适合你。具体到这个例子上来看,从个人技能的角度来看,如果你已经熟练掌握了Python或PHP中的一种语言,并且对该语言有深厚的理解和实践经验,那么使用这种语言接私活将更加得心应手。这里的原因可能包括多个方面。

2401_85969294的博客 533

ESP32学习笔记06-UART 的485 通讯模式

通信方式选择UART 控制器支持多种通信模式,使用函数 uart_set_mode() 可以选择模式。选择特定模式后,UART 驱动程序将处理已连接 UART 设备的相应行为。例如,主机开始向 Tx FIFO 缓冲区写入数据时,UART 驱动程序会自动置位 RTS 管脚(逻辑 1);最后一位数据传输完成后,驱动程序就会取消置位 RTS 管脚(逻辑 0)。要使用此模式,软件。

Car12 2476

深入理解java虚拟机

深入理解java虚拟机笔记文档JVM运行时数据区(JVM Runtime Area)

zzz的博客 278

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

《深入理解Java虚拟机》导读

​ 简介: ​ 介绍初学者如何快速学习阅读《深入理解Java虚拟机》书籍。 书籍PDF:深入理解Java虚拟机:(第3版).pdf · UITC/save-paper - Gitee.com.pdf)

yzy_cb的博客 525

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

《Thinking In Java》 VS 《Effective Java》 VS 《深入理解Java虚拟机》

今天刚考完试,在5天以前的前4个月时间里,我很庆幸自己选了一个看书的学习途径。从上个学期的暑假到现学期的11周里面,读了《Thinking In Java》、《深入理解Java虚拟机》和《Effective Java》,感悟颇多。首先先说明一下,我以前是看视频学习的,就做过两三个学校的网站,都已经上线在使用。没做过什么特别高大上的东西,所以我是处在新手的角度去读书的,我也知道自己的理解很浅,不

小浩子的博客 2万+

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

深入理解Java虚拟机第三版来袭

Java是目前最流行的语言之一,作为一个Java工程师更应该深入了解一下Java虚拟机,而支持Java程序运行的虚拟机资料并不多。当时在网上没有找到什么资源,直到我看到周志明老师的《深入理解Java虚拟机》,这简直是Java程序员的福音。第一次见到这本书是在同事的桌上,我顺手拿起来读了前两章,让我一直感觉非常神秘的虚拟机,终于被解开了面纱。之后便被深深地吸引,自己也入手一本,开始了学习之路。 周志...

专注的博客 1万+

深入理解Java虚拟机总结

花了几天学习完了周志明老师写的《深入理解Java虚拟机–JVM高级特性与最佳实践》一书,为更加深入的理解以及日后复习之用,写一篇总结

demonwang1025的博客 3738

《深入理解Java虚拟机》读后感

一、本书印象: 大概是入行半年后有所闻名,对于本书的相关概念很模糊,大概只有对虚拟机中的GC垃圾回收有一点印象。真正开始接触本书也是入行八九个月,因为入行半年多换了个工作,从那时起几乎所有的技术面试都有关于虚拟机的相关概念知识的提问,从此惦记在心:在新工作岗位有空闲时间必须掌握这门技术知识! 第一次接触的是电子档,其实有两本近似的入门参考资料,选择周志明的《深...

weixin_42683814的博客 579

深入理解Java虚拟机-走近Java

文章目录概述Java技术体系Java发展史Java虚拟机发展史展望Java技术的未来实战:自己编译JDK本章小结 本博客主要参考周志明老师的《深入理解Java虚拟机》第二版 读书是一种跟大神的交流。阅读《深入理解Java虚拟机》受益匪浅,对Java虚拟机有初步的认识。这里写博客主要出于以下三个目的:一方面是记录,方便日后阅读;一方面是加深对内容的理解;一方面是分享给大家,希望对大家有帮助。 ...

ThinkWon的博客 2万+

《深入理解Java虚拟机》提纲

这两天重温了下周志明大神的《深入理解Java虚拟机》第二版,真是经典中的经典,每次看都有新的收获,画了下我理解的每个章节在整个流程中的位置,括弧中的数字对应书中的章节,有问题欢迎指正。 ...

SjtuDarcy的博客 213

深入理解java虚拟机 下载_深入理解Java虚拟机

深入理解Java虚拟机电子版深入理解Java虚拟机电子版,全书共分为五大部分,统介绍了Java的技术体系、发展历程、虚拟机家族,以及动手编译JDK,了解这部分内容能对学习JVM提供良好的指引,里面还有更多的精彩内容,感兴趣的就快来下载吧内容简介《深入理解Java虚拟机:JVM高级特性与最佳实践》内容简介:作为一位Java程序员,你是否也曾经想深入理解Java虚拟机,但是却被它的复杂和深奥拒之门外?...

weixin_28831399的博客 838

深入理解JAVA虚拟机 脑图

深入理解JAVA虚拟机 最近读了《深入理解Java虚拟机》感觉,深深感受到了JAVA语言的强大。下面是整理的脑图,仅供参考。 如果看不清,链接【点击进入】

阿生 285

深入理解Java虚拟机读后感

大学专业就是计算机,后面大二开始就开始自己学习java的基本语法,自己写一些例子作为学习。后来参加工作也是以java开发为主,一直也没有深入的了解java是如何运行,也不太了解java的内存管理机制。大学课程学了C++,需要手动申请和释放内存,有 时忘记了就会导致内存泄露和溢出。学了java之后才发现原来java不用手动去做这些动作就可以自动管理内存,很好奇java是如何实现的。由于自己的英...

xiabaosen的专栏 445

jvm深入理解java虚拟机学习

各位java开发同学,在经过一段时间工作之后,可能对java虚拟机的原理还不甚了解。只是停留在使用的层面,为了更好的写出优雅高效的代码,增加自己的技术深度。经过努力收集,找到了2019年12月才出版的 《深入理解java虚拟机》第三版。供有需要的同学学习。收集资料不易,谢谢大家支持。 百度网盘地址:链接:https://pan.baidu.com/s/1JQsMv--LkwtmQJjAu0l-G...

a274433141的博客 173
上一篇: Hiernate 3.2 执行session.update或者session.delete未更新数据库
孝东
博客等级 码龄17年 21粉丝 19原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值