JVM 堆

news2024/11/26 13:44:41

堆的核心概述

  • 一个 JVM 实例只存在一个堆内存,堆也是 Java 内存管理的核心区域
  • Java 堆区在 JVM 启动的时候即被创建,其空间大小也就确定了。是 JVM 管理的最大一块内存空间
  • 堆可以处于物理上不连续的内存空间中,但是在逻辑上它应该被视为连续
  • 所有的线程共享 Java 堆,在这里还可以划分线程私有的缓冲区(Thread Local Allocation Buffer, TLAB)
  • 所有的对象实例以及数组都应该在运行时分配在堆上
  • 数组和对象可能永远不会存储在栈上,因为栈帧中保存引用,这个引用指向对象或者数组在堆中的位置
  • 在方法结束后,堆中的对象不会马上被移除,仅仅在垃圾收集的时候才会被移除
  • 堆,是 GC (Garbage Collection, 垃圾收集器) 执行垃圾回收的重点区域
/**
 * 设置堆大小 -Xms10m -Xmx10m
 */
public class HeapDemo {
    public static void main(String[] args) {
        System.out.println("start ...");

        try{
            Thread.sleep(1000000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("end ...");
    }
}

/**
 * 设置堆大小 -Xms20m -Xmx20m
 */
public class HeapDemo1 {
    public static void main(String[] args) {
        System.out.println("start ...");

        try{
            Thread.sleep(1000000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("end ...");
    }
}

HeapDemo 在 jvisualvm 查看:

HeapDemo1 在 jvisualvm 查看:

实例对象分配位置:

public class SimpleHeap {
    private int id;

    public SimpleHeap(int id) {
        this.id = id;
    }

    public void show(){
        System.out.println("My Id is " + id);
    }

    public static void main(String[] args) {
        SimpleHeap s1 = new SimpleHeap(1);
        SimpleHeap s2 = new SimpleHeap(2);

        int[] arr = new int[10];
        Object arr1 = new Object[10];
    }
}

内部结构细分:

Java 版本呢Code名称说明
Java 7 及之前Young Generationn Space新生区Young / New, 又被划分为 Eden区和 Survivor 区
Tenure generation space养老区Old / Tenure
Permanent space永久区Perm
Java 8 及之后Young Generationn Space新生区Young / New, 又被划分为 Eden区和 Survivor 区
Tenure generation space养老区Old / Tenure
Meta Space元空间Meta

设置堆内存大小与OOM

  • Java 堆区用于存储 Java 对象实例,那么堆的大小在 JVM 启动时就已经设定好了,可以通过选项 "-Xmx" 和 "-Xms" 来进行设置, "-Xms" 用于表示堆区的起始内存,等价于 -XX:InitialHeapSize、"-Xmx" 则用于表示堆区的最大内存,等价于 -XX:MaxHeapSize
  • 一旦堆区中的内存大小超过 "-Xmx" 所指定的最大内存时, 将会抛出 OutOfMemoryError 异常
  • 通常情况下会将 -Xms 和 -Xmx 两个参数配置相同的值, 其目的是为了能够在 java 垃圾回收机制清理完堆区后不需要重新分隔计算堆区的大小,从而提高性能
  • 初始内存大小:物理内存大小 / 64
  • 初始最大内存大小: 物理电脑内存大小 /4 
public class HeapSpaceInitial {
    public static void main(String[] args) {
        // 返回 Java 虚拟机中的堆内存总量
        long initialMemory = Runtime.getRuntime().totalMemory() / 1024 / 1024;

        // 返回 Java 虚拟机试图使用的最大堆内存量
        long maxMemory = Runtime.getRuntime().maxMemory() / 1024 / 1024;

        System.out.println("-Xms:" + initialMemory + "M");
        System.out.println("-Xmx:" + maxMemory + "M");

        System.out.println("系统内存大小为:" + initialMemory * 64 * 1024 + "G");
        System.out.println("系统内存大小为:" + maxMemory * 4 * 1024 + "G");
// 执行 jstat -gc 20332 需要进行延迟, -XX:+PrintGCDetails 不需要
//        try{
//            Thread.sleep(1000000);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
    }
}

由于 S0 和 S1 仅能一个存储,所以计算时会比设置的少一部分空间

 OutOfMemory 举例:

import java.util.ArrayList;
import java.util.Random;

public class OOMtest {
    public static void main(String[] args) {
        ArrayList<Picture> list = new ArrayList<>();
        while (true) {
            try{
                Thread.sleep(20);
            }catch (InterruptedException e) {
                e.printStackTrace();
            }

            list.add(new Picture(new Random().nextInt(1024 * 1024)));
        }
    }
}

class Picture{
    private byte[] pixels;

    public Picture(int length) {
        this.pixels = new byte[length];
    }

}

年轻代与老年代

  • 存储在JVM 中的Java 对象可以划分为两类: 一类是生命周期较短的瞬时对象、这类对象的创建和消亡都非常迅速,另一类对象的生命周期却非常长,在某些极端的请开给你下还能够与 JVM 的生命周期保持一致
  • Java 堆区进一步细分的话,可以划分为年轻代(YoungGen) 和 年老代(OldGen)
  • 其中年轻代又可以划分为 Eden空间、Survivor0 空间和 Survivor1 空间(有时也叫做 from 区、to 区)

配置新生代和老年代在堆结构的占比:

  • 默认 -XX:NewRatio=2,表示新生代占1,老年代占2,新生代占整个堆的 1/3
  • 可以修改 -XX:NewRatio=4,表示新生代占1,老年代占4,新生代占整个堆的 1/5
  •  在HotSpot 中,Eden 空间和另外两个 Servivor 空间缺省所占的比例是 8:1:1, 可以通过 -XX:SurvivorRatio=8 进行调整比例空间,默认值是8,实际值是6,需要显示进行配置
  • 可以使用选项 "-Xmn" 设置新生代最大内存大小,如果与设置 NewRatio 存在冲突,则以该配置为准 
/**
 * -Xms600m -Xmx600M
 */
public class EdenSurvivorTest {
    public static void main(String[] args) {
        System.out.println("我只是来打酱油~");
        try{
            Thread.sleep(1000000);
        }catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

图解对象分配过程

概述:

为新对象分配内存是一件非常严谨和复杂的任务, JVM 设计者不仅需要考虑内存如何分配、在哪里分配等问题,并且由于内存分配算法与内存回收算法密切相关,所以还需要考虑 GC 执行完内存回收后是否在内存空间中产生内存碎片

  • new 的对象先放伊甸园区。此区有大小限制
  • 当伊甸园的空间填满时,程序又需要创建对象,JVM 的垃圾回收器堆伊甸园区进行垃圾回收(Minor GC),将伊甸园区中的不再被其他对象所引用的对象进行销毁。再加载新的对象放到伊甸园区
  • 然后将伊甸园中的剩余对象移动到幸存者0区
  • 如果再次触发垃圾回收,此时上次幸存下来的放到幸存者0区的,如果没有回收,就会放到幸存者1区
  • 如果再次经历垃圾回收,此时会重新放回幸存者0区,接着再去幸存者1区
  • 默认 15次后,进入养老区,可以通过参数 -XX:MaxTenuringThreshold=<N> 进行设置

图解:

总结:

  • 针对幸存者 s0, s1区的总结: 复制之后有交换, 谁空谁是 to
  • 关于垃圾回收: 频繁在新生区收集,很少在养老区收集,几乎不再永久区 / 元空间收集

特殊情况:

常用调优工具:

  • JDK 命令行
  • Eclipse : Memory Analyzer Tool
  • Jconsole
  • VisualVM
  • Jprofiler
  • Java Flight Recorder
  • GCViewer
  • GC Easy

Minor GC、Major GC、Full GC

JVM 进行 GC时,并非每次都对上面三个内存(新生代、老年代; 方法区) 区域一起回收的,大部分时候回收的都是指新生代

针对 HotSpot VM 的实现,它里面的 GC 按照回收区域又分为两大种类型: 一种是部分收集 (Partial GC), 一种是整堆收集 (Full GC)

类型名称说明
部分收集Minor GC / Y只是新生代的(Eden \ s0, s1)垃圾收集
Major GC / Old GC只是老年代的垃圾收集, 只有CMS GC 会有单独收集老年代的行为。很多时候 Major GC 会和 Full GC 混肴使用,需要具体分辨是老年代回收还是整堆回收
Mixed GC收集整个新生代以及部分老年代的垃圾收集,目前只有 G1 GC 会有这种行为
整堆收集Full GC收集整个 Java 堆和方法区的垃圾收集

 年轻代 GC(Minor GC) 触发机制:

  • 当年轻代空间不足时,就会触发 Minor GC, 这里的年轻代满指的是 Eden 代满, Survivor 满不会引发 GC
  • 因为 Java 对象 大多都具备朝生夕灭的特性,所以 Minor GC 非常频繁,一般回收速度比较快
  • Minor GC 会引发 STW, 暂停其他用户的线程,等垃圾回收结束,用户线程才恢复运行

老年代 GC(Major GC / Full GC) 触发机制:

  • 指发生在老年代的 GC,对象从老年代消失时,我们说 "Major GC" 或 "Full GC" 发生了
  • 出现了 Major GC, 经常会伴随至少一次的 Minor GC(但非绝对的,在 Parallel Scavenge 收集器的收集策略里就有直接进行 Major GC 的策略选择过程),即在老年代空间不足时,会先尝试触发 Minor GC。如果之后空间还不足,则触发 Major GC
  • Major GC 的速度一般会比 Minor GC 慢10倍以上,STW 的时间更长
  • 如果 Major GC 后,内存还不足,就报 OOM了

Full GC 触发机制:

  • 调用 System.gc()时,系统建议执行 Full GC, 但是不必然执行
  • 老年代空间不足
  • 方法区空间不足
  • 通过 Minor GC后进入老年代的平均大小大于老年代的可用内存
  • 由Eden区、survivor space0(From Space)区向 survivor space1(To Space)区复制时,对象大于 To Space 可用内存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小

GC 日志查看:

 VM 配置 -XX:+PrintGCDetails :

import java.util.ArrayList;
import java.util.List;

public class GCTest {
    public static void main(String[] args) {
        int i = 0;
        try{
            List<String> list = new ArrayList<>();
            String a = "hello world";
            while(true) {
                list.add(a);
                a = a + a;
                i++;
            }
        }catch (Throwable t){
            t.printStackTrace();
            System.out.println("遍历次数为: " + i);
        }
    }
}

堆空间分代思想

分代是为了优化 GC 性能

内存分配策略

  • 如果对象在 Eden, 出生并经过第一次 MinorGC 后仍然存活,并且没有被 survivor 容纳的话,将被移动到 survivor 空间中,并且对象年龄设为1。对象在 survivor 区种每熬过一次 MinorGC, 年龄就增加 1 岁,当它的年龄增加到一定程度(默认为15岁,其实每个 JVM、每个 GC 都有所不同)时,就会被今生到老年代种
  • 对象今生老年代的年龄阈值,可以通过选项 -XX:MaxTenuringThreshold 来设置

针对不同年龄段的对象分配原则:

  • 优先分配到 Eden
  • 大对象直接分配到老年代,尽量避免程序中出现过多的大对象
  • 长期存活的对象分配到老年代
  • 动态对象年龄判断,如果Survivor 区中相同年龄的所有对象总和大于 Survivor 空间的一半,年龄大于或等于该年龄的对象可以直接进入老年代,无需等到 MaxTenuringThreshold 中要求的年龄
  • 空间分配担保: -XX:HandlePromotionFailure

为对象分配内存:TLAB(Thread Local Allocation Buffer)

  • 堆区的线程共享区域,任何线程都可以访问到堆区中的共享数据
  • 由于对象实例的创建在 JVM 中非常频繁,因此在并发环境下从堆中划分内存空间是线程不安全的
  • 为避免多个线程操作同一个地址,需要使用加锁等机制,进而影响分配速度

什么是 TLAB:

  • 从内存模型而不是垃圾收集的角度,对 Eden 区域继续进行划分, JVM 为每个线程分配了一个私有缓存区域,它包含在 Eden 空间内
  • 多线程同时分配内存时,使用 TLAB 可以避免一系列的非线程安全问题,同时还能够提升内存分配的吞吐量,因此我们可以将这种内存分配方式称为快速分配策略
  • 据我所知所有 OpenJDK 衍生出来的 JVM 都提供了 TLAB 的设计
  • 尽管不是所有的对象实例都能够在TLAB 中成功分配内存,但 JVM 确实是将 TLAB 作为内存分配的首选
  • 在程序中,开发人员可以通过选项 "-XX:UseTLAB" 设置是否开启 TLAB 空间
  • 默认情况下, TLAB 空间的内存非常小,仅占有整个 Eden空间的 1%, 当然我们可以通过选项 "-XX:TLABWasteTargetPercent" 设置 TLAB 空间所占用 Eden 空间的百分比大小
  • 一旦对象在 TLAB 空间分配内存失败时, JVM 就会尝试着通过使用加锁机制确保数据操作的原子性,从而直接在 Eden 空间中分配内存

堆空间的参数设置

参数说明
-XX:+PrintFlagsInitial查看所有的参数的默认初始值
-XX:+PrintFlagsFinal查看所有的参数的最终值(可能会存在修改,不再是初始值)
jinfo -flag 参数 进程IDCMD, 查看当前运行进程某参数设置情况
-Xms初始堆空间内存(默认为物理内存的 1/64)
-Xmx最大堆空间内存(默认为物理内存的 1/4)
-Xmn设置新生代的大小(初始值及最大值)
-XX:NewRatio配置新生代和老年代在堆结构的占比
-XX:SurvivorRatio设置新生代中 Eden 和 s0 / s1 空间的比例
-XX:MaxTenuringThreshold设置新生代垃圾的最大年龄
-XX:+PrintGCDetails输出详细的 GC处理日志
-XX:+PrintGC打印 gc 简要信息
-XX:HandlePromotionFailure是否设置空间分配担保,jdk7后已失效 变为只要老年代的连续空间大于新生代总大小或者历次晋升的平均大小就会进行 Minor GC,否则将进行 Full GC

堆是分配对象的唯一选择吗?

如果经过逃逸分析(Escape Analysis) 后发现,一个对象并没有逃逸出 方法的话,那么就可能被优化称栈上分配,这样就无需在堆上分配内存,也无须进行垃圾回收了,这也是最常见的对外存储技术

TaoBaoVM 其中创新的 GCIH(GC invisible heap) 技术实现 off-heap,将生命周期较长的 Java 对象从 heap 中移至 heap外,并且 GC 不能管理 GCIH 内部的 Java 对象,以此达到降低 GC 的回收频率和提升 GC 的回收效率的目的

逃逸分析概述:

  • 如何将堆上的对象分配到栈,需要使用逃逸分析手段
  • 这时一种可以有效减少 Java 程序中同步负载和内存堆分配压力的跨函数全局数据流分析算法
  • 通过逃逸分析, Java Hotspot 编译期能够分析出一个新的对象的引用的使用范围从而决定是否要将这个对象分配到堆上
  • 逃逸分析的基本行为就是分析对象动态作用域: 当一个对象在方法中被定义后,对象只在方法内部使用,则认为没有发生逃逸。当一个对象在方法中被定义后,它被外部方法所引用,则认为发生逃逸。
/**
 *  new 的对象实体是否有可能在方法外被调用
 */
public class EscapeAnalysis {
    public EscapeAnalysis obj;

    /**
     * 方法返回 EscapeAnalysis 对象,发生逃逸
     * @return
     */
    public EscapeAnalysis getInstance() {
        return obj == null? new EscapeAnalysis() : obj;
    }

    /**
     * 为成员属性,发生逃逸, obj 声明为 static 仍然发生逃逸
     */
    public void setObj(){
        this.obj = new EscapeAnalysis();
    }

    /**
     * 对象的作用域在当前方法中有效,没有发生逃逸
     */
    public void useEscapeAnalysis() {
        EscapeAnalysis e = new EscapeAnalysis();
    }

    /**
     * 引用成员变量的值,发生逃逸
     */
    public void useEscapeAnalysis1() {
        EscapeAnalysis e = getInstance();
    }
}

参数设置: 

  • 在 JDK 6u23 版本之后,HotSpot 中摩尔呢就已经开启了逃逸分析
  • 如果较早版本,选项 " -XX:+DoEscapeAnalysis " 显式开启逃逸分析。通过选项 "-XX:+PrintEscapeAnalysis" 查看逃逸分析的筛选结果

逃逸分析:代码优化

  • 栈上分配: 将堆分配转换为栈分配。如果一个对象在子程序中被分配,要使指向该对象的指针永远不会逃逸,对象可能是栈分配的候选,而不是堆分配
  • 同步省略: 如果一个对象被发现只能从一个线程被访问到,那么对于这个对象的操作可以不考虑同步
  • 分离对象或标量替换: 有的对象可能不需要作为一个连续的内存结构存放也可以被访问到,那么对象的部分(或全部)可以不存储在内存,而是存储在 CPU 的寄存器中

栈上分配:

  • JIT 编译器在编译期间根据逃逸分析的结果,发现如果一个对象并没有逃逸出方法,就可能被优化成栈上分配。分配完成后,继续在调用栈内执行,最后线程结束,栈空间被回收,局部变量对象也被回收。这样就无须进行垃圾回收了
  • 常见场景: 成员变量赋值,方法返回值,实例引用传递
/**
 * -Xmx1G -Xms1G --XX:-DoEscapeAnalysis -XX:+PrintGCDetails
 */
public class StackAllocation {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();

        for (int i = 0; i < 1000000; i++) {
            alloc();
        }
        long end = System.currentTimeMillis();

        System.out.println("花费的时间为: " + (end - start) + " ms");

        try{
            Thread.sleep(1000000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    private static void alloc(){
        User user = new User();
    }

    static class User{}
}

同步省略:

  • 线程同步的代价是相当高的,同步的后果是降低并发性和性能
  • 在动态编译同步块的时候,JIT 编译期可以借助逃逸分析来判断同步块所使用的锁对象是否只能够被一个线程访问而没有被发布到其他线程。如果没有,那么JIT 编译期在编译同步块的时候就会取消这部分代码的同步。这样就能大大提高并发性和性能。这个取消同步的过程就是同步省略,也叫锁消除
public class SynOmitTest {
    public void f(){
        Object hillis = new Object();
        synchronized (hillis){
            System.out.println(hillis);
        }
    }

    /**
     * JIT 优化后
     */
    public void omitF(){
        Object hillis = new Object();
        System.out.println(hillis);
    }

}

分离对象或标量替换:

  • 是指一个无法再分解成更小的数据的数据。 Java 中的原始数据类型就是标量
  • 可以分解的数据叫做聚合量(Aggregate),Java 中的对象就是聚合量,因为他们可以分解成其他聚合量和标量
  • 在 JIT 阶段,如果经过逃逸分析,发现一个对象不会被外界访问的话,那么经过 JIT 优化,就会把这个对象拆解成若干个其中包含的若干个成员变量来替换。这个过程就是标量替换
  • 参数 -XX:+EliminateAllocations: 开启标量替换(默认打开),允许将对象打散分散在栈上
public class ScalarTest {
    static class Point{
        private int x;
        private int y;

        public Point(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }

    private static void alloc(){
        Point point = new Point(1,2);
        System.out.println("point.x=" + point.x + "; point.y=" + point.y);
    }

    /**
     * JIT 分析后
     */
    private static void JITAlloc(){
        int x = 1;
        int y = 2;
        System.out.println("point.x=" + x + "; point.y=" + y);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/513546.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

久戴不痛的蓝牙耳机有哪些?久戴不痛的蓝牙耳机推荐

现如今的都市青年离不开什么数码产品&#xff1f;抛开手机这一答案&#xff0c;耳机肯定是第一项&#xff0c;遇到嘈杂的车流声&#xff0c;轰鸣的地铁&#xff0c;安静的图书馆&#xff0c;蓝牙耳机可以可以让人更加沉浸在自己的世界里&#xff0c;很多烧友在选购时候除了对音…

MySQL基础(二十七)性能分析工具的使用

1. 数据库服务器的优化步骤 当我们遇到数据库调优问题的时候&#xff0c;该如何思考呢&#xff1f;这里把思考的流程整理成下面这张图。 整个流程划分成了观察&#xff08;Show status&#xff09;和行动&#xff08;Action&#xff09;两个部分。字母 S 的部分代表观察&…

全网最详细,性能测试场景模型分析,从0到1实施性能测试...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 性能测试&#xf…

资深测试总结,Python接口自动化测试-数据依赖解决(详全)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 Python自动化测试&…

MyBatis学习 (一) 配置文件解析流程

MyBatis源码学习 最近在学习MyBatis的代码。记录下 首先下载下源码&#xff1a; https://github.com/mybatis/parent https://github.com/mybatis/mybatis-3 parent为父控依赖。也需要下载。 入口 InputStream inputStream null; try {// 获取配置文件inputStream Reso…

Java经典笔试题—day06

Java经典笔试题—day06 &#x1f50e;选择题&#x1f50e;编程题&#x1f95d;不要二&#x1f95d;把字符串转换成整数 &#x1f50e;结尾 &#x1f50e;选择题 (1)关于抽象类与最终类&#xff0c;下列说法错误的是&#xff1f; A. 抽象类能被继承&#xff0c;最终类只能被实…

Python、Pytest、Allure、Selenium和Jenkins实现自动化测试集成实例

下方查看历史精选文章 重磅发布 - 自动化框架基础指南pdfv1.1大数据测试过程、策略及挑战 测试框架原理&#xff0c;构建成功的基石 在自动化测试工作之前&#xff0c;你应该知道的10条建议 在自动化测试中&#xff0c;重要的不是工具 本文将介绍如何使用Python、Pytest、Allur…

燃气巡检系统

燃气管网检查是整个管网可靠运行的重要保证&#xff0c;尤其是加强天然气管道巡检管理更是重中之重。要做好管网维护工作&#xff0c;必须认真把握好每个环节&#xff0c;每个过程&#xff0c;每个细节&#xff0c;认真落实管网巡维制度等&#xff0c;而通过凡尔码管理系统可使…

程序员痛心流涕自述:“因为把自己代码给了别人,我亲手断送了自己的前程”

在求职的过程中&#xff0c;一般都会有投递简历、笔试、面试以及背调的环节&#xff0c;而在这几个环节中折戟沉沙的人也着实不少。 不少人觉得&#xff0c;在求职时简历需要优化&#xff0c;背调不能有瞒报、捏造的情况&#xff0c;而笔试面试则是纯纯的要靠硬实力。 虽然说…

MySQL基础(二十六)索引的创建与设计原则

1. 索引的声明与使用 1. 1 索引的分类 MySQL的索引包括普通索引、唯一性索引、全文索引、单列索引、多列索引和空间索引等。 从功能逻辑上说&#xff0c;索引主要有 4 种&#xff0c;分别是普通索引、唯一索引、主键索引、全文索引。 按照物理实现方式&#xff0c;索引可以分…

【Linux】shell编程之循环语句

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、循环语句二、for循环语句1.for 语句的结构2.for语句应用示例 三、while 循环语句1.while 循环语句结构2.while语句应用示例 四、until 循环五、跳出循环六、死循…

【Linux】信号的保存

信号的小细节真的很多~ 文章目录 前言一、信号的保存总结 前言 首先我们先引出一个新的概念&#xff0c;叫核心转储。linux系统提供了一种能力&#xff0c;操作系统可以将一个进程在异常的时候将核心代码部分进行核心转储&#xff0c;将内存中进程的相关数据全部dump到磁盘中&…

新版ripro全站美化子主题美化包使用说明手册

前言: 安装 Ripro 前,首先是需要先安装好 WordPress 主程序,因为 Ripro和美化包只是 WordPress 的一枚主题而已! 如何安装 WordPress 并不在本教程范围内,建议百度 如何安装好 WordPress ,但是还是想建议一下,尽量选择 Linux+php+nginx 的机器来安装 WordPress! 安装…

win部署CAS服务并使用

前提描述&#xff1a;通过本次了解cas是个什么东西&#xff0c;并使用它。 cas为oss(单点登录)的一种实现方案。要实现cas单点登录&#xff0c;首先需要部署cas的server服务。 CAS是Central Authentication Service的缩写&#xff0c;中央认证服务&#xff0c;。 一、安装CAS…

若依管理系统RuoYi-Vue:权限系统设计详解

文章目录 摘要数据库表结构设计菜单管理目录、菜单和按钮的区别菜单权限 api接口权限配置方法PreAuthorize注解介绍数据权限 前端vue权限拦截菜单权限按钮权限 摘要 若依&#xff08;RuoYi&#xff09;是一款基于Spring Boot和Vue.js开发的快速开发平台&#xff0c;它的权限管…

今天面了个阿里拿25k出来的小哥,让我见识到了什么是测试天花板

2022年堪称大学生就业最难的一年&#xff0c;应届毕业生人数是1076万。失业率超50%&#xff01; 但是我观察到一个数据&#xff0c;那就是已经就业的毕业生中&#xff0c;计算机通信等行业最受毕业生欢迎&#xff01; 计算机IT行业薪资高&#xff0c;平均薪资是文科其他岗位的…

优秀CRM系统的四个条件

如今&#xff0c;构建“以客户为中心”的经营模式&#xff0c;是许多企业提升竞争力的核心战略。CRM系统能够管理客户关系&#xff0c;提高销售线索转化率&#xff0c;帮助企业实现业绩增长。那么众多品牌中&#xff0c;CRM系统哪家公司做得更好&#xff1f; CRM做得好有哪几个…

Vue换肤主题

拷贝颜色选择组件 **ThemePicker <template><!-- navabar的换肤组件 --><el-color-pickerv-model="theme":predefine="[#409EFF,

智慧校园水电节能监管系统

现阶段各高校用电设备量多范围广&#xff0c;包含寝室、办公室、教室、会议厅、试验室、公共图书馆、运动场馆、饭堂、路面、园林绿化等地方&#xff0c;能耗极大。而且大多数节能意识薄弱&#xff0c;欠缺科学合理、科学合理的规章制度开展监管&#xff0c;造成电力能源很多消…

达索的全面的三维设计和产品开发工具CATIA V5-6R 2020版本下载与安装配置教程

目录 前言一、CATIA 安装二、CATIA更新包安装三、使用配置四、帮助文档安装&#xff08;非必要&#xff09;总结 前言 Dassault Systemes公司的CATIA软件是一种基于计算机辅助设计&#xff08;CAD&#xff09;和计算机辅助制造&#xff08;CAM&#xff09;的软件&#xff0c;用…