快速了解什么是HotSpot


1.什么是HotSpot

  • HotSpot是一款虚拟机,无论什么语言编译后产生的字节码文件只要符合HotSpot字节码规范都能在HotSpot运行

2.什么是跨平台

  • 所谓跨平台是指Java语言编写的程序编译后,可以在多个系统平台运行
  • 原理:Java程序是通过Java虚拟机在系统平台上运行的,只要给系统可以安装Java的虚拟机就可以运行Java程序

3.JVM进程内存模型(操作系统(OS)内存模型)

  • 代码段:就是存放代码的地方
  • 数据区:存放数据的地方
  • 栈:存储的都是局部变量,而且变量所属的作用域一旦结束,该变量就会自动释放
  • 堆:存储的是数组、对象(数组也可以看成对象),凡是new关键词创建的都在堆中
    在这里插入图片描述

4.JVM内存模型

    • JVM没有实体
    • 线程共享区是:方法区、堆
    • 线程独立区:Java虚拟机栈、本地方法栈、程序计数器
    • 方法区:JVM启动时被创建,用于存储虚拟机加载类的信息、常量、静态变量(jdk8以后静态属性存储在堆的Class对象上),以及编译器编译后的代码等数据,jdk7以前位于JVM的堆中,jdk8以后在操作系统的堆中
    • Java虚拟机栈:java程序是基于虚拟机栈运行,每个线程私有一块内存空间,虚拟机栈会为每个线程分配一个虚拟机栈,每个虚拟机栈中都有若干个栈帧每个栈帧存储了局部变量表、操作数栈、动态链接、返回地址。一个栈帧就对应Java代码中的一个方法,当线程执行到一个方法时,就代表这个方法对应的栈帧已经进入虚拟机栈并且处于栈顶的位置,每一个Java方法从被调用到执行结束,就对应栈帧从入栈道进栈的过程
    • 本地方法栈:本地方法栈和Java虚拟机栈是由区别的,Java虚拟机栈执行的是Java方法,本地方法栈执行的只本地方法,其他基本一致,在HotSpot中直接把本地方法栈和虚拟机栈合二为一。java调用C、C++是基于本地方法栈运行,等于栈
    • 堆:对内存用于存放对象和数组,他是JVM管理中最大的一块区域,堆内存和方法区都被所有线程共享,在虚拟机启动时创建。在垃圾回收方面,由于现在收集器基本上都采用分代收集算法,因此堆可以分为新生代(默认占1/3可更改)和老年代(默认2/3可更改)。新生代还可以分为Eden(8/10)、From Survivor(1/10)、To Survivor(1/10)
    • 程序计数器:程序计数器是一块非常小的内存空间,可以看作当前线程执行字节码的行号指示器,每个线程都有一个独立的程序计数器,因为程序计数器是私有的一块空间,此外,程序技术器是Java虚拟机规定的唯一不会内存溢出的区域

在这里插入图片描述

5.JVM内存模型各区域是如何协同工作的

  • 能力有限

6.从内存分配的角度理解堆

6.1内存池和内存碎片

  • 池:池是在计算机技术中常用的一种设计模型,其内涵在于:将程序中经常需要使用到的核心资源先申请出来,放到一个池内,由程序自己管理,这样提高资源的使用效率,也可以保证本程序占有的资源数量。经常使用的池技术包括内存池、线程池、连接池,其中尤以内存池和线程池使用做多
  • 内存池:内存池(Memory Pool)是一种动态内存分配与管理技术。通常情况下使用new、delete、malloc、free等API申请分配和释放内存,这样导致的后果就是:当程序长时间运行时,由于所申请的内存大小不定,频繁使用时会造成大量的内存碎片从而降低程序和操作系统的性能。内存池则是在真正使用内存之前,先申请一大块内存(内存池)留作备用,当我们申请内存时,从池中取出一块动态分配的内存,释放内存时,再将我们使用的内存释放到我们申请的内存池内,再次申请也可以再取出来使用。并且,尽量与周边的内存块合并。若内存池不够时,则自动扩大内存池,从操作系统中申请更大的内存池
  • 内存碎片: 在操作系统的内存管理中,造成堆利用率很低的主要原因是一种称为碎片(fragmentation)的现象,当虽然有未使用内存但不能满足分配请求时,就会出现这种现象。碎片的形式由两种:内部碎片、外部碎片
  • 内部碎片:内部碎片就是已经被分配出去并且能明确指出是属于那个进程,但却不能被利用的内存空间
  • 外部碎片:外部碎片就是还没有被分配出去并且不属于任何进程,但由于太小了无法分配给申请内存空间的新进程的内存空闲区域
  • 如何避免内存碎片:
    1.少用动态内存分配的函数(尽量使用栈空间)
    2.分配内存和释放内存尽量在同一函数中
    3.尽量一次性申请较大内存,而不要当内存不够时反复申请小内存,尽量避免内存分割
    4.尽量可能少得申请空间
    5.尽量少使用在堆上的内存空间

6.2Java对象是如何拿到内存的

  • TLAB(Thread Local Allocation Buffer):即线程本地分配缓存。这是一块每个线程私有的内存分配区域,它存在于Eden区,TLAB空间很小,默认仅占整个空间的1%,可以更改设置占比大小。不是所有对象都能在TLAB中成功分配内存,但JVM确实是将TLAB作为内存分配得首选,一旦对象在TLAB空间分配内存失败时,JVM就会尝试通过使用加锁机制确保数据操作的原子性,从而直接从Eden空间分配内存
  • TLAB的作用:
    1.为了加速对象得分配,由于对象分配在堆上并且堆是线程共享的,一次可能有多个线程在堆上申请空间,而且每一次的对象分配都必须线程同步,会使分配效率下降
    2.考虑到对象分配几乎是Java中最常用的操作,因此JVM使用TLAB这样的线程专有区域来避免多线程冲突,提高对象分配效率,称之为快速分配策略

6.3深入HotSpot看内存分配流程

  • 能力有限

7.什么是方法区、永久代、元空间

7.1他们三者之间的关系

  • 在Java虚拟机规范中,方法区在虚拟机启动之被创建,虽然方法区是堆的逻辑组成部分,但是简单的虚拟机实现可以选择不在方法区实现垃圾回收和压缩。这个版本的虚拟机规范也不限定实现方法区的内存位置和编译代码的管理策略。所以不同JVM厂商,针对自己的JVM可能有不同的方法区实现方式。在HotSPot中,设计者将方法区纳入GC分代收集。HotSpot虚拟机堆内存被分为新生代和老年代,对堆内存进行分代管理,所以HotSpot虚拟机使用者更愿意将方法区称为老年代。
  • 方法区和永久代的关系很想接口和类的关系,类实现了接口,而永久代就是HotSpot虚拟机对虚拟机规范中方法区的一种实现方法
  • 在HotSpot虚拟机中存在三种垃圾货收现象,minor GC(对新生代进行垃圾货收)、major GC(对老年代进行垃圾回收)、full GC(同时对新生代、老年代、永久代进行垃圾货收)。许多老年代垃圾回收是新生代垃圾货收触发的,所以很难将这两种垃圾回收区分开。major GC和full GC通常是等价的,收集整个GC堆

7.2永久代

  • 方法区:Java虚拟机规范
  • 永久代:Java虚拟机规范的具体实现
  • 永久代的缺点:
    1.占用堆的大小
    2.引发GC:字符串、动态字节码技术
    3.存储的类信息有限

7.3元空间

  • 元空间:Java虚拟机规范的具体实现(不等于方法区),HotSpot虚拟机在1.8之后取消了永久代,改为元空间,类的元信息被存储在元空间中。元空间没有使用堆内存,而是与堆不相连的本地内存区域,所以,理论上系统可以使用内存有多大,元空间就有多大,所以不会出现永久代存在时的内存溢出问题,这项改造也是有必要的,永久代的调优很困难,虽然可以设置永久代的大小,但很难确定一个合适的大小,因为其中因素有很多。比如,类的数量多少、常量数量的多少等。永久代中的元数据的位置也会随着一次full GC发生移动,比较消耗虚拟机性能。同时,HotSpot虚拟机的每种类型的垃圾货收器都需要特殊处理永久代中的元数据。将元数据从永久代中剥离出来,不仅实现了堆元空间的无缝管理,还可以简化Full GC以及对以后的并发隔离类元数据等方面进行优化
  • 元空间存在的问题就是碎片化

8.虚拟机栈

  • 每一个线程对应一个虚拟机栈,方法每调用一次就会创建一个栈帧
  • java虚拟机栈概述:Java虚拟机栈(Java Virtual Machine Stacks)是线程私有的,他的生命周期和线程相同。虚拟机栈描述的是Java方法执行的内存模型:栈帧(Stack Frame)是用于支持Java虚拟机进行方法调用和执行的数据结构,他是虚拟机栈中的栈元素。每个方法在执行的同时都会创建一个栈帧用于存储局部变量、操作数栈、动态链接、方法出口等信息。在编译代码时,栈帧需要多大的局部变量表、多深的操作数栈都已经完全确定,并且写入到方法表得Code属性中因此一个栈帧需要分配多大内存,不会受到程序运行期间变量数据的影响,而仅仅取决于具体的虚拟机实现。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。在JVM中,栈帧的操作只有两种:出栈和入栈。正在被线程执行的方法称为当前方法,而该方法的栈帧就称为当前帧,执行引擎运行时只对当前栈帧有效

8.1局部变量表

  • 没有作用域的变量不会存储到局部变量表里
  • 变量作用域:变量是有作用范围的,即作用域。一旦超出变量的作用域,就无法再使用这个变量,在程序中,变量一定会被定义在某一对大括号里,该大括号所包含的代码区就是这个变量的作用域。按作用域范围划分,变量分为成员变量、局部变量。
  • 成员变量:在类体内定义的变量称为成员变量,他的作用域是整个类,也就是说在这个类中都可以访问到定义的这个成员变量
  • 局部变量:在一个方法或方法内代码块中被定义的变量称为局部变量,局部变量在方法或代码块被执行时创建,在方法或代码块结束时被销毁,局部变量在进行取值前必须被初始化,否则编译错误
  • 局部变量表(Local Variable Table)是一组变量值存储空间。用于存放方法参数和方法内部定义的局部变量。在Java程序编译Class文件时就在方法的Code属性max_locals数据项中确定了该方法所需要分配的局部变量表的最大容量
  • 局部变量表的容量以变量槽(Variable Slot)为最小单位,虚拟机规范中并没有明确指出一个变量槽应占用的内存空间大小,只是很有导向性的说到每一个都应该存放一个boolean、byte、char、short、int 、float、reference、retunrnAddress类型的数据。这八种数据都可以使用32位或更小的物理内存来存放,但这种描述与明确指出“每个变量槽占用32位长度的空间内存”是有一些差别的,他运行的变量槽的长度可以随着处理器、操作系统、虚拟机不同而发生变化。只要保证使在64位虚拟机中使用了64位的物理内存空间去实现一个变量槽,虚拟机仍要使用对齐和补白得手段让内存槽在外观上看起来与32位虚拟机的一致

8.2操作数栈

  • 操作数栈(Operand Stack):也常称为操作栈,他是一个后入先出(Last in First out)栈。同局部变量表一样,操作数栈的最大深度也在编译的时候写入到Code属性的max_Stacks数据项中,操作数栈的每个元素可以是任意Java数据类型。
  • 32位数据类型所占的栈容量为1,64位数据类型所占的栈容量为2.在方法执行的任何时候,操作数栈的深度都不会超过在max_Stacks数据项中这顶的最大值
  • 当一个方法刚刚开始执行的时候,这个方法的操作数栈是空的,在方法的执行过程中,会有各种字节码指令往操作数栈中写入和提取内容,也就是出栈入栈操作。例如,在进行算术运算的时候是通过操作数栈来进行的,又或者在调用其他方法是是利用操作数栈来进行参数传参。举个栗子,整数加法的字节码指令iadd在运行的时候操作数栈最接近栈顶的两个元素已经存入了两个int型的数值,当执行这个指令时,会将这两个int值出栈并相加,然后将相加的结果入栈
  • Java虚拟机的解释执行引擎称为“基于栈的执行引擎”,其中所指的栈就是操作数栈,如果当前线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverFlowError异常

8.3动态链接

  • 每个栈帧都包涵一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态链接(Dynamic Linking)。Class文件的常量池中存有大量的符号引用,字节码中的方法调用指令就以常量池中指向方法的符号引用作为参数。这些符号引用一部分会在类加载阶段或者第一次使用的时候就转化为直接引用,这种转化称为静态解析。另外一部分在每一次运行期间转化为直接引用,这部分称为动态链接。
  • java在进行Javac编译时,并不想C、C++那样有连接这一步骤,而是在虚拟机加载Class文件时进行动态链接。也就是说,在Class文件中不会保存各个方法、字段的最终内存布局信息,因此这些字段、方法的符号引用不经过运行期转换的话无法得到真正的内存入口地址,也就无法直接被虚拟机使用。当虚拟机运行时,需要从常量池获得对应的符号引用,再在类创建时或运行时进行解析、翻译到具体的内存地址之中

8.4方法出口

  • 正常完成出口:当一个方法开始执行后,只有两种方法可以退出这个方法。第一种方式是执行引擎遇到任意一个方法返回的字节码指令,这时候可能会有返回值传递给上层的方法调用者,这中退出方式后称为正常完成出口。
  • 异常完成出口:另外一种退出方式是在方法执行过程中,并且这个异常没有在方法体内得到处理,无论是虚拟机内部产生的异常还是使用athrow字节码指令产生的异常,只要在本方法的异常表中没有搜索到匹配的异常处理器,就会导致方法推迟。这中退出方式称为异常完成出口

9.JVM如何基于虚拟机栈创建对象

  • 步骤
    1):在堆区分配内存,设置mark word(对象头)、类型指针
    2):将对象的地址压栈
    3):dup(duplicate复制,复制操作数栈栈顶的一个字,再将这个字压入栈,也就是对栈顶的内容做了备份,此时操作数栈上有连续相同的两个对象地址):1.复制栈顶元素(对象的地址),2.再次压栈。目的是给this指针赋值,不赋值指针就是空的,因为构建运行环境需要,创建栈帧、给this指针复制
    4):POP(作用返回栈顶的值)出栈顶元素,给局部变量赋值

10.int、double是如何在栈帧中存储的

  • 一个变量槽在64bit 、43bit都默认大小4B
  • 一个int需要一个变量槽,一个double需要两个变量槽

11.类加载机制

  • 一般我们把类从加载到内存到卸载处内存的整个过程分为七个阶段:加载、验证、准备、解析、初始化、使用、卸载。其中验证、准备、解析统称为连接
  • 在这几个阶段中,加载、验证、准备、初始化、和卸载这五个顺序是固定的,而解析阶段不一定,他有时候可能会在初始化之后,这是为了支持Java的运行时绑定。需要特别注意这里的顺序指的是按顺序开始,而不是按顺序进行或者完成,因为这些阶段通常会相互交叉的混合进行。

11.1加载

  • 加载分为三步
    1)通过一个类的全限定名来获取此类的二进制字节流
    2)将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
    3)在内存中生成一个代表这个类的Class对象,作为方法区这个类的各种数据访问入口

11.2验证

  • 验证阶段是非常重要但非必要的一个阶段,如果确保代码对程序运行期没有影响,则可以关闭大部分验证,以缩短类的加载总时间
  • 验证是连接的第一步,这一阶段的主要目的就是确保Class文件流的信息符合虚拟机规范,并且不会危害虚拟机安全。验证阶段一般分为四个阶段:
    1)文件格式验证:验证二进制字节流是否符合Class文件格式规范,确保能被虚拟机处理
    2)元数据验证:对字节码描述的信息进行语义分析,保证其描述的信息符合Java语言规范
    3)字节码验证:对类的方法体进行验证,确保语义是否合法、符合逻辑
    4)符号引用验证:发生在符号引用转换为直接引用的时候。实际的转换动作,发生在后面的解析阶段,主要对类自身以外的信息进行匹配性校验。

11.3准备

  • 准备阶段是类变量分配内存并设置初始值的阶段,这里的类变量指的是被static修饰的变量,而不包括实例变量,类变量被分配都方法区中,而实例变量存放在堆中。

11.4解析

  • 解析阶段是将常量池中的符号引用转换为直接引用的过程。
  • 解析动作主要针对类或接口、字段、类方法、接口方法、方法属性、方法句柄、调用点限定符7类符号引用

11.4.1符号引用

  • 符号引用是一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义的定位到目标即可。
  • 在JVM的模型中,也提到了符号引用,它存在于常量池中,包括类和接口的全限定名、字段的名称和描述符、方法的名称和描述符

11.4.2直接引用

  • 直接引用可以是直接指向目标的指针、相对偏移量或是一个能间接定位到目标的句柄

11.5初始化

  • 这是类加载的最后一步,到这才真正开始执行Java代码。在准备阶段,已经为类变量分配内存并赋值了默认值。在初始阶段,则可以根据需要来赋值了,可以说初始化阶段是执行类构造器方法的过程

11.5.1类构造器方法

  • 该方法是在类加载的初始化阶段执行,是对静态变量、静态代码块的初始化

11.5.2实例构造器方法

  • 该方法是new一个对象,即调用类的constructor方法时才会执行,是对非静态变量进行的初始化

12.HSDB工具

  • HSDB是一个很强大的JVM运行时状态分析工具,他可以查看并分析当前项目所生成的类和类的具体数据,包括内存地址、虚方法表等

13.常量池

  • 常量池,也叫Class常量池(常量池==Class常量池),Java文件被编译称Class文件,Class文件中除了包含类的版本、字段、方法、接口等描述信息外,还有一项就是常量池。常量池是当Class文件被Java虚拟机加载进来后存放方法区各种字面量和符号引用

13.1运行时常量池

  • 运行时常量池是方法区的一部分。运行时常量池是当Class文件被加载到内存后,Java虚拟机会将Class文件常量池里的内容转移到运行时常量池里。运行时常量池相当于Calss文件常量池的另外一个重要特征是具备动态性。Java语言并不要求常量一定只有编译期才能产生,也就是并非预置入Class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中

13.2静态常量池

  • 静态常量池是编译器编译Java代码之后所产生的常量,这里的常量跟编写代码的常量不同,指的是类、接口、方法和字段的描述,比如类的名称和其基类。“静态”,是因为他们只是一个Class的描述信息而已,还没有具备被执行的能力。在该Class文件被JVM装在完成之后,静态常量池的内容将被解析,并放到运行时常量池中。动态常量池和静态常量池可以类比程序和进程的关系,静态常量池中的内容只是编译之后的产物,所以其不保存在方法区中

13.3字符串常量池

  • 字符串常量池又称为:字符串池,全局字符串池。在工作中String类是我们使用频率非常高的一种对象类型。JVM为了提升性能和减少内存开销,避免字符串的重复创建,其维护了一块特殊的内存空间,这就是我们今天要探讨的核心:字符串常量池。字符串常量池是由String类私有维护的

14.Klass模型

  • 提供一个与Java类对等的C++类型描述
  • 提供虚拟机内部的函数分发机制

14.1oop-Klass模型

  • JVM内部基于oop-Klass模型描述一个Java类,将一个Java类分为两个本分进行描述,其中第一个模型是oop,第二个模型是Klass
  • JVM使用oop-Klass模型来描述一个Java类,虽然模型有两个,但是确实从三个不同的角度去看待Java类的:
    1)实例角度:JVM使用oop保存用户的实例数据
    2)元数据角度:JVM将类的元数据保存到了Klass模型中
    3)方法分发规则:为了实现多态,JVM采用了vtable、itable技术、而他们就保存在Klass模型中

15.内存溢出(out of memory)

  • 通俗理解就是内存不够,指程序要求的内存超出了系统所能分配的范围,通常在运行大型软件或游戏时,软件或游戏所需要的内存远远超出了你主机内安装的内存所承受的大小,就叫内存溢出。

16.内存泄漏(memory Leak)

  • 指程序中已动态分配的堆内存由于某种原因程序未释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重的后果。一次内存泄漏的危害可以忽略,但内存泄漏堆积后果很严重,无论多少内存,迟早被占光。因此可以推出内存泄漏可以导致内存溢出
  • 二者的关系:内存溢出会抛出异常,内存泄漏不会抛出异常,大多数时候程序看起来是正常运行的
  • 内存泄漏八种情况:
    1)静态集合类:如HashMap、LinkList静态容器,他们的生命周期和程序一致,则容器中的对象在程序结束之前将不能被释放,从而造成内存泄漏。长生命周期的对象持有短生命周的引用也能导致其不能被回收致使内存泄漏
    2)各种链接,数据库链接、网络链接、IO链接:在对数据库进行操作的过程中首先需要建立与数据库的连接,当不再使用时,需要调用close方法来释放与数据库的连接。只有连接被关闭垃圾回收器才会回收对应的对象。否则,将会造成大量的对象无法被回收,从而引起内存泄漏
    3)变量不合理的作用域:一般而言,一个变量的定义的作用范围大于其使用范围,很有可能造成内存泄漏。另一方面,如果没有及时地把对象设置为null,很可能导致内存泄漏的发生
    4)内部类持有外部类:如果一个外部类的实例对象的方法返回一个内部类的类实例对象,这个内部类被长期引用,即使那个外部类实例对象不再使用,但由于内部类持有外部类的实例对象,这个外部类对象将不会被回收,这也会造成内存泄漏
    5)改变哈希值:当一个对象被存入HashSet集合中以后,就不能修改这个对象中参与计算的哈希值字段,否则与最初哈希值不同就导致集中检索对象时返回找不到对象的结果,就导致无法单独删除该对象造成内存泄漏
    6)过期引用:如果一个栈现实增长,然后收缩,从栈中弹出的对象不会被当作垃圾回收,即使不在引用这些对象。因为栈内部维护着这些对象的过期引用。过期引用指永远不会被解除的引用。并且给对象所引用的其他对象也不会被回收。解决方法是清空引用即可
    7)缓存泄漏:一旦把对象引用放到缓存中,就很容易被遗忘
    8)监听器和回调:如果客户端在你实现的API中注册回调,却没有现实取消,那么就会积聚

17.JVM调优

  • JVM调优目标:使用较小的内存占用来获得较高的吞吐量或者较低延迟
  • 程序在上线前测试或者运行时会出现JVM问题,CPU Load过高、请求延迟、TPS降低、内存泄漏(垃圾回收时间变长、回收频率变高、回收效率变低)、内存溢出,因此需要对JVM进行调优,提高用户体验和运行效率
  • 重要的指标:
    1)内存占用:程序正常运行需要占用的内存大小
    2)延迟:由于垃圾收集而引起的程序停顿时间
    3)吞吐量:用户程序运行时间占用户程序和垃圾回收占用总时间的比值
  • 当然,和CPA原则一样,同时满足一个程序内存占用小、延迟低、高吞吐量是不可能的,程序的目标不同,调优时考虑的方向也不同,在调优之前必须结合实际场景,明确调优目标找到性能瓶颈进行针对性优化,最后进行测试,通过各种监控工具确认调优后结果是否满足目标

17.1JVM调优依据

  • 调优可以依赖和参考的数据有系统运行日志、堆栈错误信息、GC日志、线程快照、堆转储快照等
    1)系统运行日志:系统运行日志就是在程序代码中打印出的日志,描述了代码级别的系统运行轨迹(指行的方法、入参、返回值等),一般系统出现问题先查看系统运行日志
    2)堆栈错误信息:当系统出现问题,可以根据堆栈错误信息初步确定问题所在位置
    3)GC日志:通过记录的GC日志可以分析每块内存区域GC的频率、时间等,从而发现问题针对性优化
    4)线程快照:根据线程快照可以查看线程某一时刻的状态,当系统中可能存在请求超时、死循环、死锁等情况时,可以根据线程快照进一步确定问题
    5)堆转储快照:当程序发生内存溢出时,把当时的内存快照以文件形式进行转储,事后对当时内存使用情况进行分析

17.2JVM调优工具

  • jps(JVM Process Status):可以查看虚拟机启动时的所有进程、执行主类的全名、JVM启动参数
  • jstst(JVM Statistic Monitoring Tool):监视虚拟机信息
  • map(Memory Map For Java):查看堆内存信息,可以打印堆中每个类的实例对象和内存占用
  • jconsole、jvisualvm:分析内存信息,各Eden、Survivor、old等内存变化情况

17.3JVM经验

  • 新生代尽量设置大一些,让对象在新生代多存活一段时间,对新生代垃圾回收时尽可能多回收垃圾对象,防止或延迟对象进入老年代的机会,以前少程序Full GC频率
  • 老年代如果采用CMS收集,新生代可以不用太大,因为CMS的并行收集很快,收集过程比较耗时的并发标记和并发清除阶段都可以与用户线程并发执行
  • 方法区大小的设置,只要差不多能装下启动时和后期动态加载的类的信息就行
  • 避免创建过大的对象及数组:过大的对象及数组在新生代中没有足够空间容纳时会直接进入老年代,如果是短命的大对象会提前出发Full GC、
  • 避免同时加载大量数据:如果一次从数据库中读取大量数据,或者从Excel中读取大量记录,可以分批读取,用完尽快清空引用
  • 当集合中有对象引用,使用后应尽快把集合中的引用清空,尽快回收避免进入老年代
  • 可以在合适的场景实现缓存,采用软引用、弱引用。使用软引用发生内存溢出时,会将对象列入二次回收,如果这次回收还没有足够内存才会抛出异常
  • 避免死循环,产生死循环后,循环体内可能重复产生大量实例,导致内存空间被迅速占满
  • 尽量避免长时间等待外部资源的情况(数据库、网络、设备资源等),缩小对象的生命周期,避免进入老年代,如果不能及时返回结果可以适当采用异步处理的方式等。

18.String.intern()

  • String.intern()方法是一种手动将字符串加入常量池的方法。如果常量池中存在与调用intern()方法的字符串等值的字符串就直接返回常量池中相对应的字符串引用,否则在常量池中复制一份该字符串,并将其引用返回。该方法主要适用于程序中需要保存有限个会被反复使用的值的场景,这样可减少内存消耗,同时在进行比较操作时减少时耗,提高程序性能

19.CAP理论

  • CPA理论是分布式计算机领域的公认定理。一个分布式系统最多只能同时满足一致性(Consistency)、可用性(Availability)、分区容错(Partition tolerance),实际应用中只能三取其二

19.1一致性(Consistency)

  • 一致性指更新操作成功并返回客户端完成后,所有节点在同一时间的完全一致
  • 分布式的一致性可以从两个角度来看:
    1)客户端角度:一致性主要指的是多并发访问时更新过的数据如何获取的问题
    2)服务端角度:指的是更新如何复制分布到整个系统,以确保数据最终一致
  • 一致性是因为有并发读写才有的问题,因此在理解一致性的问题时,一定要注意结合考虑并发读写的场景
  • 从客户端角度,多进程并发访问时,更新过的数据在不同进程如何获取的不同策略。决定了不同的一致性,对于关系型数据库,要求更新过的数据被后续的访问都能看到,这是强一致。如果容忍部分或全部访问不到,则是弱一致。如果经过一段时间后要求能访问的到更新的数据,则是最终一致性。

19.2可用性(Availability)

  • 可用性指的是服务一致可用,而且是正常响应时间。
  • 对于一个可用性的分布式系统,每一个非故障的节点必须对每一个请求作出响应。所以,一般我们在衡量一个系统的可用性是,都是通过停机时间来计算的
  • 可用性分类:容错可用性、极高可用性、具有故障自动恢复能力的可用性、高可用性、商品可用性
  • 可用水平用全年停机时间来评估,好的可用性主要是指系统能过很好的为用户服务,不出现用户操作失败或者访问超时等用户体验不好的情况,一个分布式系统,上下游设计很多系统如负载均衡、WEB服务器、应用代码、数据库服务器等,任何一个节点的不稳定都可以影响可用性

19.3分区容错性(Partition Tolerance)

  • 分区容错性指当分布式系统在遇到某个节点或网络分区故障的时候,仍然能够对外提供满足一致性、可用性服务
  • 分区容错性和扩展性密切相关。在分布式应用中,可能因为一些分布式的原因导致系统无法正常运转。好的分区容错性要求能够使应用虽然是一个分布式系统,而看上去好像一个正在运转正常的整体。比如分布式系统中有一或多个机器宕机(宕(dang)机,俗称停掉机器指系统无法长时间从一个系统错误中恢复过来,或系统硬件层面出现问题,导致系统长时间无响应,而不得不重启的现象。它属于电脑运作的一种正常现象,任何电脑都会出现这种情况。比如操作系统蓝屏)了,其他的机器仍然能够正常运作满足系统需求。或者是机器之间有网络异常,将分布式系统分割未独立的几个部分,各个部分还能维持分布式系统运作,这样就具有好的分区容错性。

20.Base理论

  • Base理论是CAP理论的延伸,核心思想是即使无法做到强一致,但应用可以采用合适的方式达到最终一致
  • Base的三个组成:
    1)基本可用(Basically Available):基本可用是指分布式系统在出现故障时,允许损失部分可用性,即保证核心可用。为了应对访问量激增,部分用户可能会被引导到降级页面,服务层也可能只提供降级服务。这就是损失部分可用性的体现
    2)软状态(Soft State):软状态是指允许系统存在中间状态,而中间状态不会影响系统整体可用性。分布式存储中一般一份数据至少有三分备份,允许不同节点间副本同步的延迟就是软状态的体现。Mysql中Replication的易步复制就是这种体现
    3)最终一致性(Eventual Consistency):最终一致性是指系统中的所有数据副本经过一定时间后,最终能够达到一致的状态。弱一致和强一致相反,最终一致是弱一致的一种特殊情况。

20.1ACID和BASE

  • 区别:ACID是传统数据库常用的设计理念,追求一致性模型。BASE支持的指大型分布式系统,提出通过牺牲强一致性获取高可用性
  • 联系:ACID和BASE代表了两种截然相反地设计哲学,在分布式系统设计的场景中系统组件对一致性要求不高,因此ACID和BASE又会结合使用

21.数据一致性模型

  • 强一致性:任一时刻,所有节点的数据是一样的
  • 弱一致性:系统不保证续进程或线程的访问都会返回最新更新过的指。但会进可能保证在某个时间级别后。可以让数据达到一致性状态
  • 最终一致性:随着时间的推移,所有节点的数据最终都会保持一致,是弱一致性的衍生方案

22.Quorum、WARO机制

  • Quorum:10个副本,一次性更新三个,那么至少语言读取八个副本数据,可以保证读到最新的数据。无法实现强一致,也就是无法实现任何时刻节点都可以读到最近一次成功提交的副本数据,需要配合一个获取最新成提交地版本号的metadata服务,这样可以确定最新已经提交的版本号,然后从已经读到的数据中就可以确认最新写入的数据
  • WARO:一种简单的副本控制协议,写操作时,只有当所有的副本更新成功以后,这次写操作才算成功,否则视为失败。优先保证读,任何节点读到的数据都是最新的数据,牺牲了更新服务的可用性,只要一个副本宕机了服务就不会成功,但只要有一个节点存活,仍能提供读服务

23.Paxos算法模型

  • 是一种思想,无法直接应用到工程中
  • Paxos是一种容错的分布式一致性算法,尽管节点可能会出错,网络会发生故障或者延迟,但所有节点都会同意相同的值。目标是让所有接受者同意方案
  • Paxos中出现的角色:
    1)客户端:发起请求
    2)提议者:接受请求并之行协议,领导者为选举出来的协调者
    3)接受者:记住协议的状态,法定人数为任意大部分接受者的集合
    4)学习者:当一致意见抵达时,学习者执行请求或者发送回复给客户端

24.raft算法

  • Raft算法由leader节点来处理一致性问题。leader节点接收来自客户端的请求日志数据,然后同步到集群的其他节点进行复制,当日志已经同步到超过半数以上的节点时,leader节点再通知集群中其他节点那些日志被复制成功,可以提交到raft状态机中执行

25.zab协议

  • 通过协议来保证分布式事务的最终一致性
  • 核心是定义了事务请求的方式

26.负载均衡策略

  • 负载均衡策略将请求派发到网络中的一个或多个节点进行处理
  • 硬件负载均衡:即通过在服务器间安装专门的硬件来进行负载均衡工作
  • 软件负载均衡:即通过服务器上安装的软件来对请求进行分配派发
  • 策略种类
    1)轮询:给每个请求标记记号,之后把请求依次分发到服务器节点上。适用集群各节点提供的服务能力相等,且无状态的场景。但实际情况中各节点所能提供服务的能力并不相同,所以加权轮询对每个节点加上了权重属性。但合适的难以随实际情况的改变而改变
    2)随机:每次请求随机分法给服务器节点。缺点是在同一截面上发生碰撞的概率比较高。在非对等集群组网或者硬件配置差异较大时,各节点负载不均衡通过加权随机进行提升
    3)服务调用延迟:根据每个服务器处理请求的时间和平均时间的差异,来动态调整分法权重,可以保证服务延迟大的服务器处理更少的请求。该策略可以保证处理能力强的服务器接受到更多的请求。通过动态权重缩小服务调用时延的震荡范围,使所有请求处理的时间接近平均值。但计算平均响应时间会消耗时间滞缓请求的发出,改进后只计算最近若干次的平均时间策略
    4)一次性哈希:哈希值是32位的正整数,其值的分布范围按照一定规则分配给多个虚拟节点,虚拟节点数量至少是实际节点的两倍,实际节点根据哈希值再对虚拟节点进行瓜分,对于请求取出他们的哈希值分发到虚拟节点,虚拟节点对应的实际节点来处理请求。相同参数的请求总是发送到同一个服务提供者,当某一台服务器宕机,原本发往该节点的请求基于虚拟节点平坦到其他提供者,从而避免引起集群剧烈变动
    5)粘滞链接:主要适用于有状态的服务,同一客户端每次访问处理请求的服务器为同一台。客户端首次和服务器交互时,将链路与相应处理的服务器进行绑定,当原有服务器宕机时返回不可用消息,服务端重新为客户端绑定服务器

27.集群、分布式、SOA、微服务的概念

  • 集群:(物理形态)集群是一组相互独立的计算机,通过高速的网络组成一个计算机系统,每个集群节点都是运行其自己进程的独立服务器。对网络用户来讲,网站后端就是一个单一的系统,协同起来向用户提供系统资源、系统服务。通过网络连接组成一个组合来共同完成一个任务
  • 分布式:(工作方式)分布式系统是一个硬件或软件组件在不同网络计算机上的,彼此间仅仅通过消息传递进行通信和协议的系统,即物理上的多台主机组建成一个逻辑上的单台主机,单个节点无法提供完整服务需要多个节点协调提供服务。
  • SOA:面向服务的架构是一个组件模型(不是具体的技术,是一种开发思想),他将应用程序的不同功能单元进行拆分,并通过这些服务之间定义良好的接口和契约联系起来。接口采用中立的方式进行定义的,他应该独立于实现服务的硬件平台、操作系统和编程语言。这使得构建在各种各样系统中的服务可以以一种统一和通用的方式进行交互
  • 微服务:在SOA上进行升华,微服务架构强调的一个重点是业务需要彻底的组件化和服务化,原有的单个业务系统会拆分多个可以独立开发、设计、运行的小应用,这些小应用之间通过服务完成交互和集成。

28.TCC事务模型

  • TCC(补偿事务):Try、Confirm、Cancel
  • Try:做业务检查及资源预留
  • Confirm:做业务确认操作
  • Cancel:实现一个与Try相反的操作即回滚操作
  • TCC模型对业务的侵入性较强,改造难度较大,每个操作都需要有try、confirm、cancel三个接口实现

29.RPC

  • RPC(Remote Procedure Call):是一种进程间通信方式。就是能使应用像调用本地方法一样的调用远程的过程或服务,可以应用在分布式服务、分布式计算、远程服务调用等许多场景,业界有很多开源的优秀RPC框架
  • RPC和HTTP、RMI、Web Service都能完成远程调用,但实现方式和侧重点不通

30.Zokeeper

  • Zokeeper是源代码开放的分布式协调服务,是一个高性能的分布式数据一致性的解决方案,他的目的就是封装好的复杂容易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户

31.dubbo

  • dubbo是一个分布式服务框架,提供高性能和透明化的RPC远程服务调用方案、SOA服务治理方案,就是一个远程调用的分布式框架
  • 核心服务:
    1)远程通讯:提供对多种基于长链接的NIO框架抽象封装
    2)集群容错:提供基于接口方法的透明远程过程调用
    3)自动发现:基于注册中心目录服务,使服务消费方能动态查询服务提供方
  • dubbo实现了透明化的远程方法调用、软负载均衡及容错机制、服务自动注册与发现,采用Spring的配置方式进行配置,完全透明化接入应用,对应用没有入侵,只需要Spring加载dubbo的配置就可以了

32.终于肝完了

  • 9
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

白熊又宕机了

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值