欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

数据与内存模型 (mysql索引、JVM内存、java线程内存)

程序员文章站 2022-06-24 12:28:56
文章目录1、mysql索引1.1、索引的数据结构1.1.1、二叉树1.1.2、红黑树1.1.3、hash表1.1.4、B-Tree1.1.5、B+Tree1.2、数据表与对应的文件1.2.1、MyISM 非聚集索引1.2.2、InnoDB 聚集索引2、JVM调优基础2.1、javap 指令查看字节码文件2.2、栈(线程)2.2.1、操作数栈2.2.2、动态链接2.2、程序计数器2.3、堆2.4、方法区(元空间)2.5、本地方法栈2.6、jvisualvm 查看jvm内存空间3、多线程并发基础1、mysql...

1、mysql索引

当mysql数据量比较大的时候,查询特别慢,
我们第一个想到的解决方式应该是为数据添加索引。

索引能够高效获取数据排好序的数据结构。

1.1、索引的数据结构

5种数据结构:
二叉树、红黑树、Hash表、B-Tree、B+Tree

mysql的索引内置:Hash表、B+Tree
数据与内存模型 (mysql索引、JVM内存、java线程内存)

1.1.1、二叉树

二叉树是以单边增长的形式存储索引
数据与内存模型 (mysql索引、JVM内存、java线程内存)

查找5,要获取5次磁盘io

1.1.2、红黑树

红黑数是一种自平衡二叉查找树
例如:只有1、2
数据与内存模型 (mysql索引、JVM内存、java线程内存)
例如:只有1、2、3
数据与内存模型 (mysql索引、JVM内存、java线程内存)
例如:有1-7
数据与内存模型 (mysql索引、JVM内存、java线程内存)

查找5,要获取4次磁盘io

缺点:红黑树在数据量较大的时候高度很高,读取io的次数比较多

1.1.3、hash表

每增加一个索引,都会被hash运算一次,算出来的值就对应内存中一个具体的地址。

用运算减少io读取

hash的缺点:
1、数量较大时,哈希运算次数回变得很多,暂用cpu资源
2、做范围查找时,其他数据结构能够很快查出来,而hash要一次一次运算

1.1.4、B-Tree

B-Tree是在红黑树的基础上,增加首节点个数(首节点存在内存里)
数据与内存模型 (mysql索引、JVM内存、java线程内存)
数据与内存模型 (mysql索引、JVM内存、java线程内存)

缺点:没有解决范围查找

1.1.5、B+Tree

数据与内存模型 (mysql索引、JVM内存、java线程内存)

数据与内存模型 (mysql索引、JVM内存、java线程内存)
mysql官方对B+Tree进行了节点限制,将一个节点的大小设置成了16384个字节,也就是大约16KB。
数据与内存模型 (mysql索引、JVM内存、java线程内存)
大致的算一下,16KB/14B = 1170个索引元素。
数据与内存模型 (mysql索引、JVM内存、java线程内存)
这里高度为3,那么能存的数据量为1170x1170x16 大概为2千多万条数据

数据结构展示网址:https://www.cs.usfca.edu/~galles/visualization/Algorithms.html

1.2、数据表与对应的文件

1.2.1、MyISM 非聚集索引

frm 文件:用来存储表的结构
MYD 文件:存储所有数据行
MYI 文件:存储主键索引
数据与内存模型 (mysql索引、JVM内存、java线程内存)
数据与内存模型 (mysql索引、JVM内存、java线程内存)

1.2.2、InnoDB 聚集索引

frm 文件:用来存储表的结构
ibd 文件:用来存储索引+数据
数据与内存模型 (mysql索引、JVM内存、java线程内存)

数据与内存模型 (mysql索引、JVM内存、java线程内存)

  • InnoDB 是按照B+Tree组织的一个索引结构文件

  • InnoDB必须有主键,并且推荐使用整型自增

  • 如果你在建InnoDB表的时候,没指定主键,它会找一个能够唯一识别的字段,作为你的主键,找不到会帮你生成一个默认的索引。

  • 如果不用整型自增,用uuid做主键,会让B+Tree进行不断的分离,从而性能降低,如下

例:
数据与内存模型 (mysql索引、JVM内存、java线程内存)
数据与内存模型 (mysql索引、JVM内存、java线程内存)
使用uuid的索引,每个值大小的不确定性就会造成如上的分裂。
自增的整型会按照顺序在后面增加而不分裂

2、JVM内存模型

数据与内存模型 (mysql索引、JVM内存、java线程内存)
数据与内存模型 (mysql索引、JVM内存、java线程内存)

2.1、javap 指令查看字节码文件

第一步:打开class位置
数据与内存模型 (mysql索引、JVM内存、java线程内存)
第二步:输入指令javap -c 文件名.class > 1.txt
数据与内存模型 (mysql索引、JVM内存、java线程内存)
第三步:查看calss字节码文件
数据与内存模型 (mysql索引、JVM内存、java线程内存)
对比 jvm指令手册:https://www.cnblogs.com/qizhelongdeyang/p/12125121.html

就能知道什么意思

数据与内存模型 (mysql索引、JVM内存、java线程内存)

2.2、栈(线程)

  • 栈:程序在执行过程中存储局部变量。每个线程独享一个栈。
  • 栈帧:当程序运行过程中,每执行一个新方法,都会生成一个栈帧,这个栈帧里面存局部变量。

数据与内存模型 (mysql索引、JVM内存、java线程内存)
一个栈帧包含的内容:局部变量表、操作数栈、动态链接、方法出口
数据与内存模型 (mysql索引、JVM内存、java线程内存)

2.2.1、操作数栈

  • 可以用来操作局部变量,操作数每增加一个,就完成一个局部变量的入栈
  • 一些零时的数据操作会在操作数栈里进行
    数据与内存模型 (mysql索引、JVM内存、java线程内存)

2.2.2、动态链接

动态链接,里面存的是方法名+一个方法在方法区里的内存地址,
当一个方法被执行的时候,会去方法区寻找这个方法的地址。
数据与内存模型 (mysql索引、JVM内存、java线程内存)

2.2、程序计数器

每个线程都应该有一个程序计数器
它用来存储程序下一个执行的行
相当于它里面记录着程序现在执行到哪个位置了(class字节码中的位置)
数据与内存模型 (mysql索引、JVM内存、java线程内存)
数据与内存模型 (mysql索引、JVM内存、java线程内存)

2.3、堆

堆与栈的关系:
当栈中有一个引用类型的变量被创建时,new的内容会被放进堆,栈的这个变量存的就是对应堆里的空间地址。
数据与内存模型 (mysql索引、JVM内存、java线程内存)
数据与内存模型 (mysql索引、JVM内存、java线程内存)

2.4、方法区(元空间)

方法区里面的内容:常量+静态变量+类元信息

以前叫方法区或者持久代,jdk1.8之后叫元空间

类元信息里储存着一个类的基本信息,每一次在堆里面new的时候,都会从方法区调取类的元信息。

下面我们输出class字节码的附加信息看看
数据与内存模型 (mysql索引、JVM内存、java线程内存)
-v输出来的就多了很多常量池
数据与内存模型 (mysql索引、JVM内存、java线程内存)
数据与内存模型 (mysql索引、JVM内存、java线程内存)
元空间的数据是直接存在内存里面的

2.5、本地方法栈

本地方法栈里面存着和其他语言交换的接口
数据与内存模型 (mysql索引、JVM内存、java线程内存)
通过本地方法栈调用其他语言,这种方法目前已经不流行了,现在更多的是通过一些框架去调用

2.6、jvisualvm 查看jvm内存空间

如果配置了JDK环境变量,可以在cmd直接输入jvisualvm打开
没有配置,可以在jdk/bin目录下找到
数据与内存模型 (mysql索引、JVM内存、java线程内存)
运行一个java代码就能找到它的相关信息
数据与内存模型 (mysql索引、JVM内存、java线程内存)
数据与内存模型 (mysql索引、JVM内存、java线程内存)

3、java线程内存模型

多核CPU缓存架构
数据与内存模型 (mysql索引、JVM内存、java线程内存)
java的线程内存模型
数据与内存模型 (mysql索引、JVM内存、java线程内存)
线程的原子操作(线程从主内存中读取到工作内存中的一些操作)
数据与内存模型 (mysql索引、JVM内存、java线程内存)

3.1、工作内存和主内存

1、线程间变量互相独立
数据与内存模型 (mysql索引、JVM内存、java线程内存)

2、如果想让线程都能知道一个变量的变化,就用volatile关键字。
读取volatile类型的变量时总会返回最新写入的值。
数据与内存模型 (mysql索引、JVM内存、java线程内存)

3.2、volatile实现两个线程的工作内存变量一致

如下示例,线程1循环获取变量的值,线程2改变变量值
数据与内存模型 (mysql索引、JVM内存、java线程内存)
在没有加volatile关键字之前的线程原子操作流程图

我们发现线程2,更新变量值后会改变主内存中变量的值,但是

数据与内存模型 (mysql索引、JVM内存、java线程内存)
加上volatile关键字之后
数据与内存模型 (mysql索引、JVM内存、java线程内存)
加上volatile关键字能够实现两个线程的工作内存变量一致。
有两种实现方式
1、总线加锁(性能低)
数据与内存模型 (mysql索引、JVM内存、java线程内存)

数据与内存模型 (mysql索引、JVM内存、java线程内存)
2、MESI缓存一致性协议
数据与内存模型 (mysql索引、JVM内存、java线程内存)
cpu嗅探能够感知主内存里的变化,一旦主内存变化,就向cpu里的变量重新赋值
数据与内存模型 (mysql索引、JVM内存、java线程内存)

3.3、hsdis插件 : 将java反编译成汇编语言

首先下载hsdis插件

http://vorboss.dl.sourceforge.net/project/fcml/fcml-1.1.1/hsdis-1.1.1-win32-amd64.zip

下载完成将里面的两个文件放入java的jre/bin目录下
数据与内存模型 (mysql索引、JVM内存、java线程内存)
然后在idea中加入这个参数

-server -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssemblu -XX:Command=compileonly,*VolatileVisibilityTest.prepareData

数据与内存模型 (mysql索引、JVM内存、java线程内存)
注意上面的jre要选择hsdis-amd64.dll文件所在的那个jre。
输入的那长串参数最后的VolatileVisibilityTest指的类名,prepareData是方法名。
数据与内存模型 (mysql索引、JVM内存、java线程内存)
接下来开始运行
数据与内存模型 (mysql索引、JVM内存、java线程内存)
数据与内存模型 (mysql索引、JVM内存、java线程内存)

3.4、并发编程的三大特性

可见性、原子性、有序性

volatile保证可见性与有序性
synchronized保证原子性

volatile只能用来修饰变量

  • 可见性:当一个线程改变变量的值时,volatile保证其他线程能够感知这个改变、可见这个改变。
  • 有序性:被volatile修饰的变量的操作,会严格按照代码顺序执行(写库,查询,删除)。
  • 原子性:synchronized 关键字,代表这个方法加锁,相当于不管哪一个线程(例如线程A),运行到这个方法时,都要检查有没有其它线程B(或者C、 D等)正在用这个方法(或者该类的其他同步方法),有的话要等正在使用synchronized方法的线程B(或者C 、D)运行完这个方法后再运行此线程A

synchronized使用场景:
数据与内存模型 (mysql索引、JVM内存、java线程内存)

本文地址:https://blog.csdn.net/a__int__/article/details/110851052