JVM调优

2023-11-15

1. JVM参数分类:共分为三种

  标准参数: -开头,所有的Hotspot都支持

  分标准参数: -X开头,特定版本Hotspot支持特定命令

  不稳定: -XX开头,下个版本可能会取消

    -XX:+PrintCommandLineFlags  打印虚拟机启动时带的命令行参数

    -XX:+PrintFlagsFinal  最终参数值

    -XX:+PrintFlagsInitial  默认参数值

  java -version

  java -X

java从编译到执行

类加载子系统

加载过程 Loading

1. 双亲委派,主要出于安全来考虑

2. LazyLoading 五种情况     

–new getstatic putstatic invokestatic指令,访问final变量除外     
–java.lang.reflect对类进行反射调用时     
–初始化子类的时候,父类首先初始化     
–虚拟机启动时,被执行的主类必须初始化     
–动态语言支持java.lang.invoke.MethodHandle解析的结果为REF_getstatic REF_putstatic REF_invokestatic的方法句柄时,该类必须初始化    

3. ClassLoader的源码   

         1. findInCache -> parent.loadClass -> findClass()

    protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                }
 
                if (c == null) {
                    long t1 = System.nanoTime();
                    c = findClass(name);
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

4. 自定义类加载器

1. extends ClassLoader
2. overwrite findClass() -> defineClass(byte[] -> Class clazz)
3. 加密(通过自定义类加载器加载自加密的class,防止反编译,防止篡改)
4.parent是如何指定的,打破双亲委派
    1. 用super(parent)指定
    2. 双亲委派的打破
       1. 如何打破:重写loadClass()
       2. 何时打破过?
          1. JDK1.2之前,自定义ClassLoader都必须重写loadClass()
          2. ThreadContextClassLoader可以实现基础类调用实现类代码,通过thread.setContextClassLoader指定
          3. 热启动,热部署
             1. osgi tomcat 都有自己的模块指定classloader(可以加载同一类库的不同版本)

5. 混合执行 编译执行 解释执行

检测热点代码:-XX:CompileThreshold = 10000

解释器: bytecode intepreter (-Xint 使用解释模式,启动很快,执行较慢)

JIT: Just In-Time compiler  (-Xcomp 使用纯编译模式,执行很快,启动很慢)

混合模式: 使用解释器+热点代码编译 (默认混合模式  -Xmixed)

   开始解释执行,启动速度较快,对热点代码实时检测和编译

热点代码检测

    多次被调用的方法(方法计数器: 检测方法执行频率)

    多次被调用的循环(循环计数器: 检测循环执行频率)

    进行编译

6. 类加载范围(源码在Launcher类中)

sun.boot.class.path (Bootstrap ClassLoader类加载路径)

java.ext.dirs (ExtensionClassLoader类加载路径)

java.class.path (AppClassLoader类加载路径)

private static String bootClassPath = System.getProperty("sun.boot.class.path");
 
public static ClassLoader getAppClassLoader(final ClassLoader var0) throws IOException {
            final String var1 = System.getProperty("java.class.path");
 
private static File[] getExtDirs() {
            String var0 = System.getProperty("java.ext.dirs");

Linking(链接)

1. Verification
     1. 验证文件是否符合JVM规定
2. Preparation
     1. 静态成员变量赋默认值
3. Resolution
     1. 将类、方法、属性等符号引用解析为直接引用
        常量池中的各种符号引用解析为指针、偏移量等内存地址的直接引用

Initializing(初始化)

1. 调用类初始化代码 <clinit>,给静态成员变量赋初始值  
2. 小总结:

   1. load - 默认值 - 初始值
   2. new - 申请内存 - 默认值 - 初始值

JMM(java内存模型)

java内存模型: 线程之间的共享变量存储在主内存中,每个线程都有一个私有的本地内存,本地内存存储了该线程共享变量在主内存中的副本.线程对变量的所有操作都在工作内存中进行,而不能直接读写主内存中的数据,也不能访问其他线程的工作内存;它的工作流程就是,当一个线程A把本地内存中更新过的共享变量刷新到主内存中,另一个线程B到主内存中读取线程A已经修改的值

java内存模型的主要目的是定义程序中各种变量的访问规则,java中线程之间的通信就是由Java内存模型来控制的,JMM决定了一个共享变量的写入在什么时候是对另一个是线程可见的

在Java中的共享变量,所有的实例域,静态域和数组元素都存储在堆内存中,堆内存是所有线程共享的一块内存区域;局部变量,方法定义参数和异常处理参数是线程私有,不会被共享

硬件层数据一致性

协议很多 intel 用MESI   https://www.cnblogs.com/z00377750/p/9180644.html

现代CPU的数据一致性实现 = 缓存锁(MESI ...) + 总线锁

读取缓存以cache line为基本单位,目前64bytes

位于同一缓存行的两个不同数据,被两个不同CPU锁定,产生互相影响的伪共享问题

使用缓存行的对齐能够提高效率

伪共享

当CPU访问某个共享变量时,首先看CPU Cache中是否有该变量,如果有,则直接从中获取,否则在主存中获取该变量,把该变量所在的内存区域的一个Cache行大小的内存复制到Cache中.由于存放到Cache行的是内存块而不是单个变量,所以可能会把多个变量存放到一个Cache中.当多个线程同时修改缓存行中的多个变量的时候,同时只能有一个线程能够操作缓存行,这就是伪共享

在CPU与主内存之间存在高速缓冲存储器(Cache),一般集成在CPU内部,Cache内部是以行为单位存储,每一行称为一个Cache行,Cache行是Cache与主内存进行交换数据的基本单位,Cache行的大小一般为2的幂次方,一般为64字节

伪共享的解决方法:可以通过字节填充的方式,也可以用@sun.misc.Contended注解来解决

字节填充,也就是在创建一个变量的时候,使用填充字段来填充该变量所在的缓存行,这样就避免了将多个变量存放在了同一个缓存行中了

使用@sun.misc.Contended注解,用来解决伪共享的问题,像Thread类中的变量threadLocalRandom,threadLocalRandomProbe,threadLocalRandomSecondarySeed中就使用了这个注解,但是默认情况下,@Contended注解只用于java核心类,如rt包下面的类,如果用户需要使用这个注解,添加JVM参数-XX:-RestrictContended,填充的宽度默认为128,自定义宽度可以设置-XX:ContendedPaddingWidth参数

乱序问题

CPU为了提高指令执行效率,会在一条指令执行过程中(比如去内存读数据(慢100倍)),去同时执行另一条指令,前提是,两条指令没有依赖关系

写操作也可以进行合并

合并写技术(WC Buffer) 在寄存器和L1之间有一个WC Buffer,只有四个字节长度的大小

如何保证特定情况下不乱序

硬件内存屏障 X86CPU

sfence:  store| 在sfence指令前的写操作当必须在sfence指令后的写操作前完成。
lfence:load | 在lfence指令前的读操作当必须在lfence指令后的读操作前完成。
mfence:modify/mix | 在mfence指令前的读写操作当必须在mfence指令后的读写操作前完成。

原子指令,如x86上的”lock …” 指令是一个Full Barrier,执行时会锁住内存子系统来确保执行顺序,甚至跨多个CPU。Software Locks通常使用了内存屏障或原子指令来实现变量可见性和保持程序顺序

JVM级别如何规范(JSR133)

LoadLoad屏障:
     对于这样的语句Load1; LoadLoad; Load2,
     在Load2及后续读取操作要读取的数据被访问前,保证Load1要读取的数据被读取完毕。
StoreStore屏障:
     对于这样的语句Store1; StoreStore; Store2,
     在Store2及后续写入操作执行前,保证Store1的写入操作对其它处理器可见。
LoadStore屏障:
     对于这样的语句Load1; LoadStore; Store2,
     在Store2及后续写入操作被刷出前,保证Load1要读取的数据被读取完毕。
StoreLoad屏障:
    对于这样的语句Store1; StoreLoad; Load2,
    在Load2及后续所有读取操作执行前,保证Store1的写入对所有处理器可见。

volatile的实现细节

1. 字节码层面
   ACC_VOLATILE

2. JVM层面
   volatile内存区的读写 都加屏障

   StoreStoreBarrier        LoadLoadBarrier
   volatile 写操作             volatile 读操作
   StoreLoadBarrier         LoadStoreBarrier

3. OS和硬件层面
   https://blog.csdn.net/qq_26222859/article/details/52235930
   hsdis - HotSpot Dis Assembler
   windows lock 指令实现 | MESI实现

synchronized实现细节

1. 字节码层面
   ACC_SYNCHRONIZED
   monitorenter monitorexit
2. JVM层面
   C C++ 调用了操作系统提供的同步机制
3. OS和硬件层面
   X86 : lock cmpxchg / xxx

对象的内存布局

1. 对象的创建过程

1. class loading

2. class linking (verification,preparation,)

3. class initializing

4. 申请对象内存

5. 成员变量赋默认值

6. 调用构造方法<init>

    1. 成员变量顺序赋初始值

    2. 执行构造方法语句

2. 对象在内存中的存储布局

观察虚拟机配置

java -XX:+PrintCommandLineFlags -version
  
  

1. 普通对象

        1. 对象头:markword  8
        2. ClassPointer指针:-XX:+UseCompressedClassPointers 为4字节 不开启为8字节
        3. 实例数据
           1. 引用类型:-XX:+UseCompressedOops 为4字节 不开启为8字节
              Oops Ordinary Object Pointers
        4. Padding对齐,8的倍数

2. 数组对象

        1. 对象头:markword 8
        2. ClassPointer指针同上
        3. 数组长度:4字节
        4. 数组数据
        5. 对齐 8的倍数

3. 对象头具体包括什么

至少包括3位的锁信息,一位是否偏向锁,2位的锁标志位,GC的标记(分带年龄)

看对象的状态来真正分配这64位

1. hashcode部分

    31位hashcode->system.identityHashCode(...)

    按原始内容计算的hashcode,重写过的hashcode方法计算的结果不会放在这里

         如果对象没有重写hashcode方法,那么默认是调用os::random产生hashcode,可以调用System.identityHashCode获取

         os::random产生hashcode的规则为next_random=(16807seed)mod(2*31-1),因此可以使用31位存储;另外一旦生成了hashcode,JVM会将其记录在markword中

    当调用为重写的hashcode方法以及System.identityHashCode的时候

    GC年龄默认为15,原因是分带年龄占4位,最多到15

当一个对象计算过identityHashCode之后,不能进入偏向锁状态

4.对象怎么定位

1. 句柄池

2. 直接指针(HotSpot默认)

5. 对象怎么分配?

 栈上分配

    线程私有小对象

    无逃逸  (-XX:-DoEscapeAnalysis)

    支持标量替换  (-XX:-EliminateAllocations)

线程本地分配TLAB(Thread Local Allocation Buffer)  (-XX:-UseTLAB)

    占用eden,默认1%

    多线程的时候不用竞争eden就可以申请空间,提高效率

    小对象

老年代

    大对象

java内存区域

指令集分类

1. 基于寄存器的指令集
2. 基于栈的指令集
   Hotspot中的Local Variable Table 类似于寄存器

Runtime Data Area(运行时数据区)

PC 程序计数器

存放指令位置 每个线程一个程序计数器(线程私有)
虚拟机的运行,类似于这样的循环:
while( not end ) {
​    取PC中的位置,找到对应位置的指令;
​    执行该指令;
​    PC ++;
}

JVM Stack(虚拟机栈)

1. Frame - 每个方法对应一个栈帧 线程私有
   1. Local Variable Table(局部变量表)
   2. Operand Stack(操作数栈)
      对于long的处理(store and load),多数虚拟机的实现都是原子的
      jls 17.7,没必要加volatile
   3. Dynamic Linking(动态链接)
       https://blog.csdn.net/qq_41813060/article/details/88379473
      jvms 2.6.3
   4. return address(方法返回地址)
      a() -> b(),方法a调用了方法b, b方法的返回值放在什么地方

Heap(堆)

Method Area(方法区)

所有线程共享 ,主要是每一个class的结构,包括运行时常量池

1. Perm Space (<1.8)
   字符串常量位于PermSpace
   FGC不会清理
   大小启动的时候指定,不能变
2. Meta Space (>=1.8)
   字符串常量位于堆
   会触发FGC清理
   不设定的话,最大就是物理内存

Runtime Constant Pool(运行时常量池)

Native Method Stack(本地方法栈)

Direct Memory(直接内存或堆外内存)

JVM可以直接访问的内核空间的内存 (OS 管理的内存)
NIO , 提高效率,实现zero copy

思考:

如何证明1.7字符串常量位于Perm,而1.8位于Heap?
提示:结合GC, 一直创建字符串常量,观察堆,和Metaspace

常用指令

store (将操作数栈中的数据弹出赋值给局部变量表)

load(将局部变量表中的数据压入操作数栈)

pop(弹出操作数栈顶元素)

dmp(将操作数栈顶元素复制到栈顶)

mul

sub

invoke

1. InvokeStatic
2. InvokeVirtual
3. InvokeInterface
4. InovkeSpecial
   可以直接定位,不需要多态的方法
   private 方法 , 构造方法
5. InvokeDynamic
   JVM最难的指令
   lambda表达式或者反射或者其他动态语言scala kotlin,或者CGLib ASM,动态产生的class,会用到的指令

GC和垃圾回收器

GC的基础知识

1.什么是垃圾

没有任何引用指向的一个对象或者多个对象(循环引用)

 2.如何定位垃圾

1. 引用计数(ReferenceCount)
2. 根可达算法(RootSearching)  (Hotspot用这种)

根包括: 虚拟机栈,本地方法栈,运行时常量池,方法区的静态引用,Class问价

3.常见的垃圾回收算法

1. 标记清除(mark sweep) - 位置不连续 产生碎片 效率偏低(两遍扫描)

算法相对简单,存活对象比较多的情况下效率较高   用于(老年代cms)

2. 拷贝算法 (copying) - 浪费空间,移动复制对象,需要调整对象的引用

适用于存活对象较少的情况,只扫描一次,效率较高,没有碎片  用于(新生代都用这种)

3. 标记压缩(mark compact) - 扫描两次,需要移动对象,调整指针,效率较低

不会产生碎片,方便对象分配,不会产生内存减半

4.JVM内存分代模型(用于分代垃圾回收算法)

1. 部分垃圾回收器使用的模型

除Epsilon ZGC Shenandoah之外的GC都是使用逻辑分代模型
G1是逻辑分代,物理不分代
除此之外不仅逻辑分代,而且物理分代

2. 新生代 + 老年代 + 永久代(1.7)Perm Generation/ 元数据区(1.8) Metaspace

   1. 永久代 元数据 - Class
   2. 永久代必须指定大小限制 ,元数据可以设置,也可以不设置,无上限(受限于物理内存)
   3. 字符串常量 1.7 - 永久代,1.8 - 堆
   4. MethodArea逻辑概念 - 永久代、元数据

3. 老年代满了FGC Full GC

5. GC Tuning (Generation)

   1. 尽量减少FGC
   2. MinorGC = YGC
   3. MajorGC = FGC

6. 对象分配过程图

栈上分配

    线程私有小对象

    无逃逸  (-XX:-DoEscapeAnalysis)

    支持标量替换  (-XX:-EliminateAllocations)

线程本地分配TLAB(Thread Local Allocation Buffer)  (-XX:-UseTLAB)

    占用eden,默认1%

    多线程的时候不用竞争eden就可以申请空间,提高效率

    小对象

老年代

    大对象

7.对象何时进入老年代

1.超过-XX:MaxTenuringThreshold指定次数(YGC)

Parallel Scavenge 15

G1 15

CMS 6

2.动态年龄:(不重要)
   存活对象超过s2的50%,把超过50%的对象直接放到老年代

3. 分配担保:(不重要)
   YGC期间 survivor区空间不够了 空间担保直接进入老年代

常见的垃圾回收器

1. JDK诞生 Serial追随 提高效率,诞生了PS,为了配合CMS,诞生了PN,CMS是1.4版本后期引入,CMS是里程碑式的GC,它开启了并发回收的过程,但是CMS毛病较多,因此目前任何一个JDK版本默认是CMS
   并发垃圾回收是因为无法忍受STW

2. Serial 年轻代 串行回收

3. SerialOld

4. PS 年轻代 并行回收
5. ParNew 年轻代 配合CMS的并行回收
6. ParallelOld


7. ConcurrentMarkSweep 老年代 并发的, 垃圾回收和应用程序同时运行,降低STW的时间(200ms)

CMS问题比较多,所以现在没有一个版本默认是CMS,只能手工指定 

CMS既然是MarkSweep,就一定会有碎片化的问题,碎片到达一定程度,CMS的老年代分配对象分配不下的时候,使用SerialOld 进行老年代回收

还有就是浮动垃圾
   想象一下:
   PS + PO -> 加内存 换垃圾回收器 -> PN + CMS + SerialOld(几个小时 - 几天的STW)
   几十个G的内存,单线程回收 -> G1 + FGC 几十个G -> 上T内存的服务器 ZGC
   算法:三色标记 + Incremental Update

8. G1(10ms)
   算法:三色标记 + SATB
9. ZGC (1ms) PK C++
   算法:ColoredPointers + LoadBarrier
10. Shenandoah
    算法:ColoredPointers + WriteBarrier
11. Eplison
12. PS 和 PN区别

PS吞吐量优先 PN响应时间优先

13. 垃圾收集器跟内存大小的关系

    1. Serial 几十兆
    2. PS 上百兆 - 几个G
    3. CMS - 20G
    4. G1 - 上百G
    5. ZGC - 4T - 16T(JDK13)

1.8默认的垃圾回收:PS + ParallelOld

CMS

浮动垃圾产生于并发清理阶段,下一次垃圾回收会被回收掉

如果采用ParNew + CMS组合,怎样做才能够让系统基本不产生FGC

1.加大JVM内存

2.加大Young的比例

3.提高Y-O的年龄

4.提高S区比例

5.避免代码内存泄漏

G1(垃圾优先)

是一种服务端使用的垃圾回收器,目标是用在多核,大内存的机器上,大多数情况下可以实现指定的GC停顿时间,同时还能保持较高的吞吐量

特点:

并发收集

压缩空闲时间不会延长GC的暂停时间

更容易预测GC的停顿时间

以用于不需要实现很高的吞吐量的场景

新老年代比例

5%~60%

一般不用手工指定

也不要手工指定,因为这是G1预测停顿时间的基准

GC何时触发

YGC: eden空间不足  多线程并行执行

MixedGC XX:InitiatingHeapOccupacyPercent 默认值45%,当O超过这个值时,启动MixedGC

FGC: old空间不足  System.gc()

如果G1产生FGC,你应该做什么?

1. 扩内存
2. 提高CPU性能(回收的快,业务逻辑产生对象的速度固定,垃圾回收越快,内存空间越大)
3. 降低MixedGC触发的阈值,让MixedGC提早发生(默认是45%)

java 10 以前是串行FullGC,之后是并行FullGC

MixedGC的过程

初始标记 STW

并发标记

最终标记 STW (重新标记)

筛选回收 STW (并行)

其他算法和概念

CSet=Collection Set(G1用)

一组可被回收的分区的集合.

在CSet中存活的数据会在GC过程中被移动到另一个可用分区,CSet中的分区可以来自Eden空间,survivor空间,或者老年代.

CSet会占用不到整个堆空间的1%大小

RSet=RememberedSet 记忆集

主要用来解决跨代引用的问题

记忆集是一种用于记录从非收集区域指向收集区域的指针集合的抽象数据结构

记录了其他Region中的对象到本Region的引用,key是别的region的起始地址,value是本region中卡表的索引号

RSet的价值在于,使得垃圾收集器不需要扫描整个堆找到谁引用了当前分区中的对象,只需要扫描RSet即可

记忆集占用10%~20%的空间

Card Table 卡表

马士兵

由于做YGC时,需要扫描整个OLD区,效率非常低,所以JVM设计了CardTable, 如果一个OLD区CardTable中有对象指向Y区,就将它设为Dirty,下次扫描时,只需要扫描Dirty Card
  在结构上,Card Table用BitMap来实现

深入理解java虚拟机

主要用来解决跨代引用的问题,结构上用的字节数组

字节数组Card_Table的每一个元素都对应着其标识的内存区域中一块特定大小的内存块,这个内存块被称为"卡页", Hotspot卡页大小为2的9次幂

并发标记算法

三色标记法

白色: 未被标记的对象

灰色: 自身被标记,成员变量未被标记

黑色: 自身和成员变量均已标记完成

 漏标的两个充要条件

在remark过程中,黑色指向了白色

灰色指向白色的引用没了

打破漏标的两个条件之一即可

1. incremental update  增量更新,关注引用的增加,(CMS用这种)

把黑色对象重新标记为灰色,下次重新扫描属性

2. STAP snapshot at the beginning -关注引用的删除 (G1用这种)

当B->D消失时,要把这个引用推到GC的堆栈,保证D还能被GC扫描到

JVM调优

调优前的基础概念:

1. 吞吐量:用户代码时间 /(用户代码执行时间 + 垃圾回收时间)
2. 响应时间:STW越短,响应时间越好

所谓调优,首先确定,追求啥?吞吐量优先,还是响应时间优先?还是在满足一定的响应时间的情况下,要求达到多大的吞吐量...

问题:

科学计算,吞吐量。数据挖掘,thrput。吞吐量优先的一般:(PS + PO)

响应时间:网站 GUI API (1.8 G1)

什么是调优?

1. 根据需求进行JVM规划和预调优
2. 优化运行JVM运行环境(慢,卡顿)
3. 解决JVM运行过程中出现的各种问题(OOM)

调优,从规划开始

调优,从业务场景开始,没有业务场景的调优都是耍流氓
无监控(压力测试,能看到结果),不调优

步骤:
  1. 熟悉业务场景(没有最好的垃圾回收器,只有最合适的垃圾回收器)
     1. 响应时间、停顿时间 [CMS G1 ZGC] (需要给用户作响应)
     2. 吞吐量 = 用户时间 /( 用户时间 + GC时间) [PS]
  2. 选择回收器组合
  3. 计算内存需求(经验值 1.5G 16G)
  4. 选定CPU(越高越好)
  5. 设定年代大小、升级年龄
  6. 设定日志参数
     1. -Xloggc:/opt/xxx/logs/xxx-xxx-gc-%t.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=20M -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCCause
     2. 或者每天产生一个日志文件
  7. 观察日志情况

JVM调优第一步,了解JVM常用命令行参数

JVM的命令行参数参考:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html

HotSpot参数分类

  标准: - 开头,所有的HotSpot都支持
  非标准:-X 开头,特定版本HotSpot支持特定命令
  不稳定:-XX 开头,下个版本可能取消

java -version

java -X

  1. 区分概念:内存泄漏memory leak,内存溢出out of memory
  2. java -XX:+PrintCommandLineFlags HelloGC
  3. java -Xmn10M -Xms40M -Xmx60M -XX:+PrintCommandLineFlags -XX:+PrintGC  HelloGC
     PrintGCDetails PrintGCTimeStamps PrintGCCauses
  4. java -XX:+UseConcMarkSweepGC -XX:+PrintCommandLineFlags HelloGC
  5. java -XX:+PrintFlagsInitial 默认参数值
  6. java -XX:+PrintFlagsFinal 最终参数值
  7. java -XX:+PrintFlagsFinal | grep xxx 找到对应的参数
  8. java -XX:+PrintFlagsFinal -version |grep GC

生产环境中能够随随便便的dump吗?

     小堆影响不大,大堆会有服务暂停或卡顿(加live可以缓解),dump前会有FGC

常见的OOM问题有哪些?

     栈 堆 MethodArea 直接内存

优化环境,常用案例

1.硬件升级,系统反而变慢

有一个50万PV的资料类网站(从磁盘提取文档到内存)原服务器32位,1.5G
   的堆,用户反馈网站比较缓慢,因此公司决定升级,新的服务器为64位,16G
   的堆内存,结果用户反馈卡顿十分严重,反而比以前效率更低了
   1. 为什么原网站慢?
      很多用户浏览数据,很多数据load到内存,内存不足,频繁GC,STW长,响应时间变慢
   2. 为什么会更卡顿?
      内存越大,FGC时间越长
   3. 咋办?
      PS -> PN + CMS 或者 G1

2. 系统CPU经常100%,如何调优?

   CPU100%那么一定有线程在占用系统资源,
   1. 找出哪个进程cpu高(top)
   2. 该进程中的哪个线程cpu高(top -Hp)
   3. 导出该线程的堆栈 (jstack)
   4. 查找哪个方法(栈帧)消耗时间 (jstack)
   5. 工作线程占比高 | 垃圾回收线程占比高

3. 系统内存飙高,如何查找问题?

  1. 导出堆内存 (jmap)
   2. 分析 (jhat jvisualvm mat jprofiler ... )

4. 如何监控JVM

   1. jstat jvisualvm jprofiler arthas top...

5. 案例

 案例1:垂直电商,最高每日百万订单,处理订单系统需要什么样的服务器配置?

   这个问题比较业余,因为很多不同的服务器配置都能支撑(1.5G 16G)
 
   1小时360000集中时间段, 100个订单/秒,(找一小时内的高峰期,1000订单/秒)
 
   经验值,
 
   非要计算:一个订单产生需要多少内存?512K * 1000 500M内存
 
   专业一点儿问法:要求响应时间100ms
 
   压测!

 案例2:12306遭遇春节大规模抢票应该如何支撑?

   12306应该是中国并发量最大的秒杀网站:
   号称并发量100W最高
   CDN -> LVS -> NGINX -> 业务系统 -> 每台机器1W并发(10K问题) 100台机器
   普通电商订单 -> 下单 ->订单系统(IO)减库存 ->等待用户付款
   12306的一种可能的模型: 下单 -> 减库存 和 订单(redis kafka) 同时异步进行 ->等付款
   减库存最后还会把压力压到一台服务器
   可以做分布式本地库存 + 单独服务器做库存均衡
   大流量的处理方法:分而治之

* 怎么得到一个事务会消耗多少内存?

   1. 弄台机器,看能承受多少TPS?是不是达到目标?扩容或调优,让它达到
   2. 用压测来确定

解决JVM运行中的问题(完整步骤)

1.测试代码

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
 
/**
 * 从数据库中读取信用数据,套用模型,并把结果进行记录和传输
 */
 
public class TestFullGC {
 
    private static class CardInfo {
        BigDecimal price = new BigDecimal(0.0);
        String name = "张三";
        int age = 5;
        Date birthdate = new Date();
 
        public void m() {
        }
    }
 
    private static ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(50,
            new ThreadPoolExecutor.DiscardOldestPolicy());
 
    public static void main(String[] args) throws Exception {
        executor.setMaximumPoolSize(50);
        for (; ; ) {
            modelFit();
            Thread.sleep(100);
        }
    }
 
    private static void modelFit() {
        List<CardInfo> taskList = getAllCardInfo();
        taskList.forEach(info -> {
            // do something
            executor.scheduleWithFixedDelay(() -> {
                //do sth with info
                info.m();
            }, 2, 3, TimeUnit.SECONDS);
        });
    }
 
    private static List<CardInfo> getAllCardInfo() {
        List<CardInfo> taskList = new ArrayList<>();
 
        for (int i = 0; i < 100; i++) {
            CardInfo ci = new CardInfo();
            taskList.add(ci);
        }
 
        return taskList;
    }
}

2. java -Xms200M -Xmx200M -XX:+PrintGC com.mashibing.jvm.gc.T15_FullGC_Problem01

3. 一般是运维团队首先受到报警信息(CPU Memory)

4. top命令观察到问题:内存不断增长 CPU占用率居高不下

5. top -Hp 观察进程中的线程,哪个线程CPU和内存占比高

6. jps定位具体java进程
   jstack 定位线程状况,重点关注:WAITING BLOCKED
   eg.查死锁
   waiting on <0x0000000088ca3310> (a java.lang.Object)
   假如有一个进程中100个线程,很多线程都在waiting on <xx> ,一定要找到是哪个线程持有这把锁
   怎么找?搜索jstack dump的信息,找<xx> ,看哪个线程持有这把锁RUNNABLE

7. 为什么阿里规范里规定,线程的名称(尤其是线程池)都要写有意义的名称
   怎么样自定义线程池里的线程名称?(自定义ThreadFactory)

8. jinfo pid    打印进程状态

9. jstat -gc 动态观察gc情况 / 阅读GC日志发现频繁GC / arthas观察 / jconsole/jvisualVM/ Jprofiler(最好用)
   jstat -gc 4655 500 : 每个500个毫秒打印GC的情况
   怎么定位OOM问题的?不能用图形界面,影响性能
   1:已经上线的系统不用图形界面用什么?(cmdline arthas)
   2:图形界面到底用在什么地方?测试!测试的时候进行监控!(压测观察)

10. jmap - histo 4655 | head -20,查找有多少对象产生

11. jmap -dump:format=b,file=xxx pid :

    线上系统,内存特别大,jmap执行期间会对进程产生很大影响,甚至卡顿(电商不适合)
    1:设定了参数HeapDump,OOM的时候会自动产生堆转储文件
    2:很多服务器备份(高可用),停掉这台服务器对其他服务器不影响
    3:在线定位(一般小点儿公司用不到)

12. java -Xms20M -Xmx20M -XX:+UseParallelGC -XX:+HeapDumpOnOutOfMemoryError com.mashibing.jvm.gc.T15_FullGC_Problem01

13. 使用MAT / jhat /jvisualvm 进行dump文件分析
     https://www.cnblogs.com/baihuitestsoftware/articles/6406271.html
jhat -J-mx512M xxx.dump
    http://192.168.17.11:7000
    拉到最后:找到对应链接
    可以使用OQL查找特定问题对象
14. 找到代码的问题

arthas在线排查工具

为什么需要在线排查?
   在生产上我们经常会碰到一些不好排查的问题,例如线程安全问题,用最简单的threaddump或者heapdump不好查到问题原因。为了排查这些问题,有时我们会临时加一些日志,比如在一些关键的函数里打印出入参,然后重新打包发布,如果打了日志还是没找到问题,继续加日志,重新打包发布。对于上线流程复杂而且审核比较严的公司,从改代码到上线需要层层的流转,会大大影响问题排查的进度。
使用方式:

进入arthas目录,使用命令 java -jar arthas-boot.jar 启动arthas,会找到对应进程,输入进程号,会把arthas挂在对应进程上面,然后可以通过命令查看进程状态

jvm  观察jvm详细配置信息
thread 列出当前进程有多少个线程 定位线程问题
Thread + 线程号  列出具体线程的信息
dashboard 观察系统情况,类似于top命令

heapdump 到处堆转储文件,类似于jmap的转储功能
heapdump + jhat分析

    jhat -J-mx512M xxx.dump
        http://192.168.17.11:7000
        拉到最后:找到对应链接
        可以使用OQL查找特定问题对象
jad反编译
   动态代理生成类的问题定位
   第三方的类(观察代码)
   版本问题(确定自己最新提交的版本是不是被使用)
redefine 热替换
   目前有些限制条件:只能改方法实现(方法已经运行完成),不能改方法名, 不能改属性
   m() -> mm()
sc  - search class
watch  - watch method
没有包含的功能:jmap

案例汇总

1. 硬件升级系统反而卡顿的问题(见上)

2. 线程池不当运用产生OOM问题(见上)
   不断的往List里加对象(实在太LOW)

4. tomcat http-header-size过大问题(Hector)

5. lambda表达式导致方法区溢出问题(MethodArea / Perm Metaspace)
   LambdaGC.java     -XX:MaxMetaspaceSize=9M -XX:+PrintGCDetails

6. 直接内存溢出问题(少见)
   《深入理解Java虚拟机》P59,使用Unsafe分配直接内存,或者使用NIO的问题

7. 栈溢出问题
   -Xss设定太小
8. 比较一下这两段程序的异同,分析哪一个是更优的写法:


  
  
  1. Object o = null;
  2. for( int i= 0; i< 100; i++) {
  3. o = new Object();
  4. //这种更好
  5. }
  6. for( int i= 0; i< 100; i++) {
  7. Object o = new Object();
  8. }

9. 重写finalize引发频繁GC
   小米云,HBase同步系统,系统通过nginx访问超时报警,最后排查,C++程序员重写finalize引发频繁GC问题
为什么C++程序员会重写finalize?(new delete)
   finalize耗时比较长(200ms)
   
10. 如果有一个系统,内存一直消耗不超过10%,但是观察GC日志,发现FGC总是频繁产生,会是什么引起的?
    System.gc() (这个比较Low)

11. Distuptor有个可以设置链的长度,如果过大,然后对象大,消费完不主动释放,会溢出

12. 用jvm都会溢出,mycat用崩过,1.6.5某个临时版本解析sql子查询算法有问题,9个exists的联合sql就导致生成几百万的对象

13. new 大量线程,会产生 native thread OOM,(low)应该用线程池,
    解决方案:减少堆空间(太TMlow了),预留更多内存产生native thread
    JVM内存占物理内存比例 50% - 80%

日志解析

PS GC日志详解

每种垃圾回收器的日志格式是不同的!

PS日志格式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0Q5iXJUl-1621865321029)(./GC日志详解.png)]

heap dump部分:

```java
eden space 5632K, 94% used [0x00000000ff980000,0x00000000ffeb3e28,0x00000000fff00000)
                            后面的内存地址指的是,起始地址,使用空间结束地址,整体空间结束地址
```

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZWXltCKE-1621865321031)(GCHeapDump.png)]

total = eden + 1个survivor

CMS的问题

1. Memory Fragmentation(内存碎片)

    -XX:+UseCMSCompactAtFullCollection
    -XX:CMSFullGCsBeforeCompaction 默认为0 指的是经过多少次FGC才进行压缩

2. Floating Garbage(浮动垃圾)

    Concurrent Mode Failure
    产生:if the concurrent collector is unable to finish reclaiming the unreachable objects before the tenured generation fills up, or if an allocation cannot be satisfiedwith the available free space blocks in the tenured generation, then theapplication is paused and the collection is completed with all the applicationthreads stopped
    解决方案:降低触发CMS的阈值
    PromotionFailed
    解决方案类似,保持老年代有足够的空间
    –XX:CMSInitiatingOccupancyFraction 92% 可以降低这个值,让CMS保持老年代足够的空间

CMS日志分析

执行命令:java -Xms20M -Xmx20M -XX:+PrintGCDetails -XX:+UseConcMarkSweepGC com.study.jvm.gc.T15_FullGC_Problem01

[GC (Allocation Failure) [ParNew: 6144K->640K(6144K), 0.0265885 secs] 6585K->2770K(19840K), 0.0268035 secs] [Times: user=0.02 sys=0.00, real=0.02 secs]

// ParNew:年轻代收集器
// 6144->640:收集前后的对比
//(6144):整个年轻代容量
// 6585 -> 2770:整个堆的情况
//(19840):整个堆大小
[GC (CMS Initial Mark) [1 CMS-initial-mark: 8511K(13696K)] 9866K(19840K), 0.0040321 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
    //8511 (13696) : 老年代使用(最大)
    //9866 (19840) : 整个堆使用(最大)
[CMS-concurrent-mark-start]
[CMS-concurrent-mark: 0.018/0.018 secs] [Times: user=0.01 sys=0.00, real=0.02 secs]
    //这里的时间意义不大,因为是并发执行
[CMS-concurrent-preclean-start]
[CMS-concurrent-preclean: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
    //标记Card为Dirty,也称为Card Marking
[GC (CMS Final Remark) [YG occupancy: 1597 K (6144 K)][Rescan (parallel) , 0.0008396 secs][weak refs processing, 0.0000138 secs][class unloading, 0.0005404 secs][scrub symbol table, 0.0006169 secs][scrub string table, 0.0004903 secs][1 CMS-remark: 8511K(13696K)] 10108K(19840K), 0.0039567 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
    //STW阶段,YG occupancy:年轻代占用及容量
    //[Rescan (parallel):STW下的存活对象标记
    //weak refs processing: 弱引用处理
    //class unloading: 卸载用不到的class
    //scrub symbol(string) table:
        //cleaning up symbol and string tables which hold class-level metadata and
        //internalized string respectively
    //CMS-remark: 8511K(13696K): 阶段过后的老年代占用及容量
    //10108K(19840K): 阶段过后的堆占用及容量

[CMS-concurrent-sweep-start]
[CMS-concurrent-sweep: 0.005/0.005 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
    //标记已经完成,进行并发清理
[CMS-concurrent-reset-start]
[CMS-concurrent-reset: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
    //重置内部结构,为下次GC做准备

G1日志详解

[GC pause (G1 Evacuation Pause) (young) (initial-mark), 0.0015790 secs]
//young -> 年轻代 Evacuation-> 复制存活对象
//initial-mark 混合回收的阶段,这里是YGC混合老年代回收
   [Parallel Time: 1.5 ms, GC Workers: 1] //一个GC线程
      [GC Worker Start (ms):  92635.7]
      [Ext Root Scanning (ms):  1.1]
      [Update RS (ms):  0.0]
         [Processed Buffers:  1]
      [Scan RS (ms):  0.0]
      [Code Root Scanning (ms):  0.0]
      [Object Copy (ms):  0.1]
      [Termination (ms):  0.0]
         [Termination Attempts:  1]
      [GC Worker Other (ms):  0.0]
      [GC Worker Total (ms):  1.2]
      [GC Worker End (ms):  92636.9]
   [Code Root Fixup: 0.0 ms]
   [Code Root Purge: 0.0 ms]
   [Clear CT: 0.0 ms]
   [Other: 0.1 ms]
      [Choose CSet: 0.0 ms]
      [Ref Proc: 0.0 ms]
      [Ref Enq: 0.0 ms]
      [Redirty Cards: 0.0 ms]
      [Humongous Register: 0.0 ms]
      [Humongous Reclaim: 0.0 ms]
      [Free CSet: 0.0 ms]
   [Eden: 0.0B(1024.0K)->0.0B(1024.0K) Survivors: 0.0B->0.0B Heap: 18.8M(20.0M)->18.8M(20.0M)]
 [Times: user=0.00 sys=0.00, real=0.00 secs]
//以下是混合回收其他阶段
[GC concurrent-root-region-scan-start]
[GC concurrent-root-region-scan-end, 0.0000078 secs]
[GC concurrent-mark-start]
//无法evacuation,进行FGC
[Full GC (Allocation Failure)  18M->18M(20M), 0.0719656 secs]
   [Eden: 0.0B(1024.0K)->0.0B(1024.0K) Survivors: 0.0B->0.0B Heap: 18.8M(20.0M)->18.8M(20.0M)], [Metaspace: 38
76K->3876K(1056768K)] [Times: user=0.07 sys=0.00, real=0.07 secs]

常用参数

常见垃圾回收器组合参数设定:(1.8)

-XX:+UseSerialGC = Serial New (DefNew) + Serial Old
  小型程序。默认情况下不会是这种选项,HotSpot会根据计算及配置和JDK版本自动选择收集器
-XX:+UseParNewGC = ParNew + SerialOld
  这个组合已经很少用(在某些版本中已经废弃)
  https://stackoverflow.com/questions/34962257/why-remove-support-for-parnewserialold-anddefnewcms-in-the-future
-XX:+UseConcurrentMarkSweepGC = ParNew + CMS + Serial Old
-XX:+UseParallelGC = Parallel Scavenge + Parallel Old (1.8默认) 【PS + SerialOld】
-XX:+UseParallelOldGC = Parallel Scavenge + Parallel Old
-XX:+UseG1GC = G1
Linux中没找到默认GC的查看方法,而windows中会打印UseParallelGC
  java +XX:+PrintCommandLineFlags -version
  通过GC的日志来分辨

Linux下1.8版本默认的垃圾回收器到底是什么?

  1.8.0_181 默认(看不出来)Copy MarkCompact
  1.8.0_222 默认 PS + PO

GC常用参数

-Xmn -Xms -Xmx -Xss
  年轻代 最小堆 最大堆 栈空间
-XX:+UseTLAB
  使用TLAB,默认打开
-XX:+PrintTLAB
  打印TLAB的使用情况
-XX:TLABSize
  设置TLAB大小
-XX:+DisableExplictGC
  System.gc()不管用 ,FGC
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintHeapAtGC
-XX:+PrintGCTimeStamps
-XX:+PrintGCApplicationConcurrentTime (低)
  打印应用程序时间
-XX:+PrintGCApplicationStoppedTime (低)
  打印暂停时长
-XX:+PrintReferenceGC (重要性低)
  记录回收了多少种不同引用类型的引用
-verbose:class
  类加载详细过程
-XX:+PrintVMOptions
-XX:+PrintFlagsFinal  -XX:+PrintFlagsInitial
  必须会用
-Xloggc:opt/log/gc.log
-XX:MaxTenuringThreshold
  升代年龄,最大值15
锁自旋次数 -XX:PreBlockSpin 热点代码检测参数-XX:CompileThreshold 逃逸分析 标量替换 ...
  这些不建议设置

Parallel常用参数

-XX:SurvivorRatio
-XX:PreTenureSizeThreshold
  大对象到底多大
-XX:MaxTenuringThreshold
-XX:+ParallelGCThreads
  并行收集器的线程数,同样适用于CMS,一般设为和CPU核数相同
-XX:+UseAdaptiveSizePolicy
  自动选择各区大小比例

CMS常用参数

-XX:+UseConcMarkSweepGC
-XX:ParallelCMSThreads
  CMS线程数量
-XX:CMSInitiatingOccupancyFraction
  使用多少比例的老年代后开始CMS收集,默认是68%(近似值),如果频繁发生SerialOld卡顿,应该调小,(频繁CMS回收)
-XX:+UseCMSCompactAtFullCollection
  在FGC时进行压缩
-XX:CMSFullGCsBeforeCompaction
  多少次FGC之后进行压缩
-XX:+CMSClassUnloadingEnabled
-XX:CMSInitiatingPermOccupancyFraction
  达到什么比例时进行Perm回收
GCTimeRatio
  设置GC时间占用程序运行时间的百分比
-XX:MaxGCPauseMillis
  停顿时间,是一个建议时间,GC会尝试用各种手段达到这个时间,比如减小年轻代

G1常用参数

-XX:+UseG1GC
-XX:MaxGCPauseMillis
  建议值,G1会尝试调整Young区的块数来达到这个值
-XX:GCPauseIntervalMillis
  ?GC的间隔时间
-XX:+G1HeapRegionSize
  分区大小,建议逐渐增大该值,1 2 4 8 16 32。
  随着size增加,垃圾的存活时间更长,GC间隔更长,但每次GC的时间也会更长
  ZGC做了改进(动态区块大小)
G1NewSizePercent
  新生代最小比例,默认为5%
G1MaxNewSizePercent
  新生代最大比例,默认为60%
GCTimeRatio
  GC时间建议比例,G1会根据这个值调整堆空间
ConcGCThreads
  线程数量
InitiatingHeapOccupancyPercent
  启动G1的堆空间占用比例

强软弱虚四大引用

强引用: 指程序代码之中普遍存在的引用赋值,只要强引用关系还存在,垃圾收集器永远不会回收被引用的对象

软引用:用来描述一些还有用但是非必须的对象,被软引用关联着的对象,在系统将要发生内存溢出前,会把这些对象列入回收范围进行二次回收,也就是当空间不够了,才进行回收(SoftReference)

用途:软引用可用于缓存,没有容器

弱引用:弱引用用来描述哪些非必须的对象,只要垃圾回收器开始回收,一定会回收弱引用所指向的对象(WeakReference)

用途:一般用在容器中

虚引用:是一种最弱的引用,一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象的实例

用途:对象死后的后事操作,用于管理直接内存,会给垃圾回收线程一个通知。虚引用所指向的那个对象被回收的时候,会被扔到一个应用队列中,对检测到队列中的对象有被回收了,对象它是否使用了堆外内存,有就回收堆外内存

当对象被回收时,通过Queue可以检测到,然后清理堆外内存

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JVM调优 的相关文章

  • Java动态澄清

    我在术语下看到了这段摘录Java 流行语在读一本关于Java的书时我不明白 Dynamic Java 程序带有大量的运行时类型信息 用于在运行时验证和解析对对象的访问 这使得以安全且方便的方式动态链接代码成为可能 这对于 Java 环境的稳
  • JVM跳转指令的偏移量怎么会是32768呢?

    在写一个回答有关 JVM 字节码偏移量的问题 https stackoverflow com a 30240357 3182664 我注意到 javac 的行为和生成的类文件中有一些我无法解释的内容 当编译这样的类时 class FarJu
  • IntelliJ 调试:暂停整个虚拟机,然后进入单线程

    我正在调试一个具有大量线程的应用程序 我的断点设置为暂停整个虚拟机 当线程遇到其中一个断点时 我想使用 Step Over 但这似乎会恢复整个虚拟机 直到该步骤完成 如果我可以只单步执行到达断点的单个线程 那确实会有帮助 在 Intelli
  • 病毒或机器故障导致“无法创建Java虚拟机”?

    我用的是双核XP机安装了 4GB 内存 但仅2 5GB由于 32 位事实 由操作系统报告 我正在积极修改旧的 JAVA 应用程序至少一个月 使用最新的Eclipse 编辑 构建和运行 和Ant 另一种构建和运行的方式 在里面Eclipse运
  • 集群环境下的Spring Singleton

    正如中所讨论的this https stackoverflow com questions 1194129 singleton in cluster environmentpost 不适合使用单例聚集的环境 因为不同 JVM 中有多个单例对
  • Java 堆被无法访问的对象淹没

    我们的 Java EE 应用程序开始出现一些严重问题 具体来说 应用程序在启动后几分钟内就运行了高达 99 的老年代堆 不会抛出 OOM 但实际上 JVM 没有响应 jstat 显示老年代的大小根本没有减少 没有垃圾收集正在进行 并且kil
  • 如何在JVM不退出的情况下多次运行Java程序?

    假设我有一个Java程序Test class 如果我使用下面的脚本 for i in 1 10 do java Test done JVM每次都会退出java Test被调用 我想要的是跑步java Test在不退出JVM的情况下多次执行
  • 使用 + 符号连接字符串

    今天我在读书Antonio 关于 toString 性能的博客 https antoniogoncalves org 2015 06 30 who cares about tostring performance 还有一段话 昨天曾经被认为
  • 我的代码中出现内存不足异常

    作为 Oracle 数据库压力测试的一部分 我正在长时间运行代码并使用 java 版本 1 4 2 简而言之 我正在做的是 while true Allocating some memory as a blob byte data new
  • 非活动状态下的 Spring Boot 堆使用情况

    我在本地部署了一个非常简单的 spring boot 应用程序 它只有一个类 控制器 差不多就这样了 我注意到堆分配并不稳定 并且有峰值和突然下降 为什么会这样 我没有对应用程序进行过一次调用 A view from VisualVM 事实
  • 如何减少Scala中创建的对象数量?

    我正在 Scala 中编写一个计算机图形应用程序 它使用 RGB 类返回图像中某个点的颜色 正如你可以想象的 返回颜色 RGB 对象的函数被调用了很多次 class RGB val red Int val green Int val blu
  • 什么触发了java垃圾收集器

    我对 Java 中垃圾收集的工作原理有点困惑 我知道当不再有对某个对象的实时引用时 该对象就有资格进行垃圾回收 但是如果它有对实时对象的引用怎么办 可以说我有一个节点集合 它们再次引用更多节点 List 1 gt Node a gt Nod
  • Intellij Idea 使用什么 JVM 来启动?

    我是 Eclipse 用户 最近决定尝试 Intellij Idea 我的操作系统是 Ubuntu 12 使用 Eclipse 时 可以通过在 eclipse ini 中指定来轻松选择用于启动 Eclipse 的 JVM http wiki
  • JVM 是否会内联对象的实例变量和方法?

    假设我有一个非常紧密的内部循环 每次迭代都会访问和改变一个簿记对象 该对象存储有关算法的一些简单数据 并具有用于操作它的简单逻辑 簿记对象是私有的和最终的 并且它的所有方法都是私有的 最终的和 inline 下面是一个示例 Scala 语法
  • jvm 如何以及何时何地更改 Linux 的最大打开文件值?

    在linux中 每个登录用户的每个进程的最大打开文件数有限制 如下所示 ulimit n 1024 当我学习java nio时 我想检查这个值 因为channel在Linux中也是一个文件 所以我编写了一个客户端代码来不断创建socketC
  • 使用 javac 和 javax.tools.JavaCompiler 有什么区别?

    Maven 编译器插件文档states http maven apache org plugins maven compiler plugin 编译器插件用于编译项目的源代码 从 3 0 开始 默认编译器是 javax tools Java
  • OQL 包中的所有实例

    是否有可能在OQL检索属于一个包的所有对象 或者我可以查询wildcards 正如 haridsv 建议我尝试过的 SELECT from com example and SELECT a from com example but in V
  • UseCompressedOops JVM 标志有什么作用以及何时应该使用它?

    HotSpot JVM 标志是什么 XX UseCompressedOops我应该做什么以及什么时候使用它 在 64 位 Java 实例上使用它 与不使用它 时 我会看到什么样的性能和内存使用差异 去年大多数 HotSpot JVM 都默认
  • Java 语言中不可用的字节码功能

    当前 Java 6 是否有一些事情可以在 Java 字节码中完成而在 Java 语言中无法完成 我知道两者都是图灵完备的 所以将 可以做 理解为 可以做得更快 更好 或者只是以不同的方式 我正在考虑额外的字节码 例如invokedynami
  • JVM:是否可以操作帧堆栈?

    假设我需要执行N同一线程中的任务 这些任务有时可能需要来自外部存储的一些值 我事先不知道哪个任务可能需要这样的值以及何时 获取速度要快得多M价值观是一次性的而不是相同的M值在M查询外部存储 注意我不能指望任务本身进行合作 它们只不过是 ja

随机推荐

  • MYSQL8-快速生成表结构(用于生成文档)

    MYSQL8 快速生成表结构 用于生成文档 SELECT rownum rownum 1 AS 序号 column name AS 代码 CASE WHEN column comment IS NULL OR TRIM column com
  • C语言技巧 ----------调试----------程序员必备技能

    作者前言 作者介绍 作者id 老秦包你会 简单介绍 喜欢学习C语言和python等编程语言 是一位爱分享的博主 有兴趣的小可爱可以来互讨 个人主页 小小页面 gitee页面 秦大大
  • 解决端口被占用问题,安装MySQL出现端口被占用

    1 快捷键 Win R 打开命令提示符 输出命令 netstat ano 目的 查看占用3306端口的 PID 值 上图可以看出 占用3306 窗口的 PID值为 13620 2 打开任务管理器 点击 详细信息 选中该程序 鼠标右键 点击
  • 密度聚类DBSCAN、主成分分析PCA算法讲解及实战(附源码)

    需要源码请点赞关注收藏后评论区留言私信 一 基于密度的聚类 基于密度的聚类算法的主要思想是 只要邻近区域的密度 对象或数据点的数目 超过某个阀值 就把它加到与之相近的聚类中 也就是说 对给定类中的每个数据点 在一个给定范围的区域中必须至少包
  • 操作系统最全面试题汇总

    1 操作系统的特点 共享 资源可被多个并发执行的进程使用 并发 可以在同一时间间隔处理多个进程 需要硬件支持 异步 进程走走停停 每次执行的速度不一样 但是要保证进程每次执行结果相同 虚拟 将物理实体映射成为多个虚拟设备 操作系统的组成 驱
  • Python中的pandas库简介及其使用

    pandas模块 pandas是一个强大的分析结构化数据的工具集 它的使用基础是Numpy 提供高性能的矩阵运算 用于数据挖掘和数据分析 同时也提供数据清洗功能 Pandas中常见的数据结构有两种 Series DateFrame 类似一维
  • 股票相关信息

    股票开头数字代表什么 600 开头的股票是上证 A股 属于大盘股 其中 6006 开头的股票是 最早上市的股票 6016开头的股票为大盘蓝筹股 900 开头的股票是上证 B股 000 开头的股票是深证 A股 001 002开头的股票也都属于
  • C++11尝鲜:右值引用和转发型引用

    C 11尝鲜 右值引用和转发型引用 2013 10 05 19 52 5979人阅读 评论 4 收藏 举报 分类 C 33 版权声明 本文为博主原创文章 未经博主允许不得转载 目录 右值引用 为了解决移动语义及完美转发问题 C 11标准引入
  • 软考高项学习教程【第一阶段】:第1章-信息系统开发基础【考点笔记1】

    文章目录 前言 一 信息系统开发基础 1 1 信息系统与信息化 1 信息系统建设 信息与信息系统的概念 2 信息系统的类型 了解 3 信息系统的生命周期 产品生命周期 重要 4 信息系统规划方法 5 信息系统开发方法 考点 5 1 结构化方
  • To install it, you can run: npm install --save module

    简直就是有毛病 和智障无异 吃了个午饭 VUE项目突然就不能运行了 报了个错 说让我npm install save module 报错如下 在main js文件中莫名其妙多了个webpack的引入 导致这个报错 然后按照提示我安装了这个m
  • Mac M1下安装、升级npm(国内源)

    我们介绍使用Homebrew安装node npm等环境 brew的安装见如下文章 Mac M1芯片电脑Java开发环境准备 重要的事情说三遍 国内源 国内源 国内源 要不然慢的要死 要卡死 npm我们也要使用国内源 安装很简单还是之前的套路
  • Asp.net 之Cookie简单介绍与使用

    什么是Cookie Cookie 有时也用其复数形式Cookies 指某些网站为了辨别用户身份 进行session跟踪而储存在用户本地终端上的数据 通常经过加密 所以查看浏览器保存到本地的Cookie时 一般都是一个文本文件这些文件通常是以
  • 为什么InnoDB使用B+树而不是B树

    出于对IO性能的考虑 B树每个节点都存储数据 而B 树只有叶子节点才存储数据 所以在查询相同数据量的情况下 B树的IO会更频繁 因为索引本身存储在磁盘上 当数据量大时 就不能把整个索引全部加载到内存 只能逐一加载每一个磁盘页 更何况B树的索
  • 【性能测试】第四篇

    主流性能测试工具 1 Loadrunner HP Loadrunner 是一种工业级标准性能测试负载工具 可以模拟上万用户实施测试 并在测试时可实时检测应用服务器及服务器硬件各种数据 来确认和查找存在的瓶颈 支持多协议 WEB HTTP H
  • Python+Selenium实现短视频自动上传与发布

    前言 最近有人对自动上传与发布很感兴趣 都私下找我说了好几次了 今天 必须把他安排 必须实力宠粉 本篇依次介绍目前主流的短视频平台 抖音 快手 B站 小红书 微视 百度好看视频 西瓜视频 微信视频号 搜狐视 频 一点号 大风号 趣头条等 的
  • # 若依-点击重置清空table列表,不刷新数据

    若依点击清空按钮 清空table数据 思路 点击清空按钮 触发输入框清空 并且移除列表中所有数据 实战 找到ry ui js新增restNoRefresh函数 ry ui js路径 src main resources static ruo
  • FPGA 频率计实验

    参考 正点原子开拓者 FPGA 开发指南 数字频率计是一种基本的测量仪器 被广泛应用于航天 电子 测控等领域 基于传统测频原理的频率计的测量精度将随被测信号频率的下降而降低 在使用中有较大的局限性 而等精度频率计不但具有较高的测量精度 而且
  • Jfinal报错Can not create instance of class: demo.DemoConfig

    根据文档demo 启动项目时报错 WARN oejuc AbstractLifeCycle FAILED jfinal java lang RuntimeException Can not create instance of class
  • vector对象的定义和初始化以及vector迭代器iterator

    vector对象的定义和初始化 vector类定义了好几种构造函数 用来定义和初始化vector对象 vector
  • JVM调优

    1 JVM参数分类 共分为三种 标准参数 开头 所有的Hotspot都支持 分标准参数 X开头 特定版本Hotspot支持特定命令 不稳定 XX开头 下个版本可能会取消 XX PrintCommandLineFlags 打印虚拟机启动时带的