文章字数:251,阅读全文大约需要1分钟
java native interface JNA(Java Native Access)框架是一个开源的Java框架,是SUN公司主导开发的,建立在经典的JNI的基础之上的一个框架
1 |
|
文章字数:251,阅读全文大约需要1分钟
java native interface JNA(Java Native Access)框架是一个开源的Java框架,是SUN公司主导开发的,建立在经典的JNI的基础之上的一个框架
1 |
|
文章字数:251,阅读全文大约需要1分钟
JMH
是JDK9
自带的JVM
基准测试套件,用于定位代码性能,执行时间、吞吐量等
maven
依赖引入1 | <dependency> |
maven
工程(官方推荐)1 | mvn archetype:generate |
1 | // 预热5次,每次1s |
Mean + Units
就是每次操作的毫秒数
1 | Benchmark Mode Samples Mean Mean error Units |
@BenchmarkMode(Mode.Throughput)
和 @OutputTimeUnit(TimeUnit.MILLISECONDS)
组合,就是每毫秒吞吐量
943.437 ops/ms
1 | Benchmark Mode Samples Mean Mean error Units |
文章字数:250,阅读全文大约需要1分钟
jni(java native interface)允许java和本地方法交互,但是会丧失平台的可移植性。
java native
方法1 | public class HelloWorld { |
javac
编译java类1 | javac HelloWorld.java |
javah
生成头文件1 | javah HelloWord |
javah
生成的头文件声明方法相同的方法。HelloWorldImpl.cpp
1 | # include "jni.h" |
1 | static { |
文章字数:1076,阅读全文大约需要4分钟
java内存模型(java Memory Model)是一种符合内存模型规范,屏蔽硬件及操作系统的差异,保证java程序在不同平台下的内存访问效果一致性的机制及规范。
本文整理自-深入理解JVM-内存模型(jmm)和GC的上半部分
随着cpu的发展,内存的读写速度远远赶不上cpu。因此,cpu的厂商在每颗cpu上加上了高速缓存,作为cpu和内存间的缓冲区域。
2.带来的问题
每个cpu各自的一套缓存(一级缓存、二级缓存、三级缓存),如何保证多处理器运算到同一个内存区域时的数据一致性?
为了解决这个问题,各个处理器需要遵循缓存一致性协议与主存交互
在cpu层面,内存屏障(Memory Barrier)提供了支持(硬件层支持):
硬件层的内存屏障分为:
Load Barrier
(读屏障)和Store Barrier
(写屏障)
1.cpu执行指令可能是;无序的,内存屏障可以组织屏障两侧进行指令重排。
2.强制把写缓冲区/高速缓存中的数据失效,从而强制从主存中获取。
使用关键词volatitle修饰变量
相当于变量读写加锁
1 | public class VolatitleValue { |
1.可见性,该变量的读一定可以看到读之前最后的写
2.原子性,对于该变量的读写具有原子性。
jvm主要有 sun的
HotSpot/JRockit
和IBM的IBMJVM
,其中HotSpot为主流,在此探讨HotSpot虚拟机。
如开题所说,jmm是jvm的一种规范。使语言不能直接访问硬件内存,作为中转以解决各硬件和操作系统的差异问题。
1 | 方法区、堆是线程共享的 |
线程执行java方法时指向字节码,方便cpu线程切换时切换回正确位置
注:内存中唯一没有OutOfMemoryError的区域
2 虚拟机栈
由栈帧组成,每个方法执行的时候都会创建栈帧存储变量表,操作栈,动态链接,方法出入口等。
注:方法调用入栈,调用完出栈。局部变量表大小在方法运行前就完全确定了
虚拟机栈调用的是java方法(字节码文件),本地方法栈则是调动native方法(c、c++)的实现方法
以下为线程共有的
一般来说对象实例及数组都是在堆上被分配内存。堆作为最大的内存区域也是GC(内存回收机制)主要管理的区域。根据规范,堆可以存在与物理上不连续的内存空间,可设定固定大小也可扩展。(-Xmx和-Xms)。
注:没有内存可分配会报OOM(OutOfMemory)
存储已被虚拟机加载的类信息、常量、静态变量、静态方法、静态代码块。
再回顾一下
线程私有的:
区域名 | 作用 |
---|---|
计数器 | cpu线程切换后找到正确位置 |
jvm栈 | 引用java方法 |
native栈 | 引用本地c/c++方法及功能 |
线程共享的:
区域名 | 作用 |
---|---|
堆 | 对象实例、数组 |
方法区 | 类的静态信息 |
1 | 1.对象头// |
对象头(markword)说明:
- 64操作系统下16字节(开启指针压缩12)
- synchronized的锁信息就存储在这里
- 根据锁位偏移有四种锁状态
无锁态
、偏向锁
、轻量级锁
、重量级锁
文章字数:1244,阅读全文大约需要4分钟
1. 减少`minor gc`的频率,将转移到老年代的对象数量降低到最新
2. 减少`full gc`次数
3. 找到并提升性能瓶颈
1 | -verbose.gc:显示GC的操作内容。打开它,可以显示最忙和最空闲收集行为发生的时间、收集前后的内存大小、收集需要的时间等。 |
1 | # 新生代和老年代一般内存比例为 1:2 |
Minor GC
执行时间不超过50ms
Minor GC
执行频率在10s
一次以上Full GC
执行时间不到1s
Full GC
执行频率在10
分钟一次以上jps
: JVM Process Status Tool
, 显示指定系统内所有的HotSpot虚拟机进程。jstat
: JVM statistics Monitoring
, 是用于监视虚拟机运行时状态信息的命令,它可以显示出虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。jmap
: JVM Memory Map
用于生成heap dump
文件。jhat
: JVM Heap Analysis Tool
, 与jmap
搭配使用,用来分析jmap
生成的dump
,jhat
内置了一个微型的HTTP/HTML
服务器,生成dump
的分析结果后,可以在浏览器中查看。jstack
: 用于生成java
虚拟机当前时刻的线程快照。jinfo
: JVM Configuration info
实时查看和调整虚拟机运行参数。javap
: 查看经javac
之后产生的JVM
字节码代码,自动解析.class
文件, 避免了去理解class
文件格式以及手动解析class
文件内容。jcmd
: 几乎集合了jps
、jstat
、jinfo
、jmap
、jstack
所有功能,一个多功能工具, 可以用来导出堆, 查看Java
进程、导出线程信息、 执行GC
、查看性能相关数据等。jconsole
: Java Monitoring and Management Console
, 监控内存,线程和类jvisualvm
: 全能工具,可以分析内存快照、线程快照;监控内存变化、GC变化等MAT
: Memory Analyzer Tool
, Java heap分析工具,它可以帮助我们查找内存泄漏和减少内存消耗, 基于EclipseGChisto
: 分析gc日志的工具HotSpot
的JVM
里,具有访问权限的java
进程的具体状态1 | jps [options] [hostid] |
heap dump
文件,如果不使用这个命令,可以使用-XX:+HeapDumpOnOutOfMemoryError
参数来让虚拟机出现OOM
时自动生成dunp
文件文章字数:476,阅读全文大约需要1分钟
SpringBoot中可以使用jpa整合ElasticSearch
jdk 1.8
ElasticSearch 2.4
需要和springBoot版本匹配com.sun.jna
1 | spring-boot-starter-data-elasticsearch |
data-elasticsearch的依赖自带了ES的jar,如果不配置ES实例SpringBoot会自动生成一个。但是性能不如自己搭建的。
1 | spring: |
1 | @Data //lombok |
@Document
加在类上类型 | 属性名 | 默认值 | 说明 |
---|---|---|---|
String | indexName | 无 | 索引库的名称,建议以项目的名称命名 |
String | type | “” | 类型,建议以实体的名称命名 |
short | shards | 5 | 默认分区数 |
short | replica | 1 | 每个分区默认的备份数 |
String | refreshInterval | “1s” | 刷新间隔 |
String | indexStoreType | “fs” | 索引文件存储类型 |
@Field
属性上加的,相当于@Column
,可以不写,默认全部添加到ES中。主键上是@Id
。类型 | 属性名 | 默认值 | 说明 |
---|---|---|---|
FieldType | type | FieldType.Auto | 自动检测属性的类型 |
FieldIndex | index | FieldIndex.analyzed | 默认情况下分词 |
boolean | store | false | 默认情况下不存储原文 |
String | searchAnalyzer | “” | 指定字段搜索时使用的分词器 |
String | indexAnalyzer | “” | 指定字段建立索引时指定的分词器 |
String[] | ignoreFields | {} | 如果某个字段需要被忽略 |
1 | @Repository |
文章字数:1807,阅读全文大约需要7分钟
JIT
编译等运行数据1 | jstat [ generalOption | outputOptions vmid [ interval[s|ms] [ count ] ] |
-statOption
统计参数1 | class #显示有关类加载器行为的统计信息。 |
其它参数
1 | -h n #每n个样本(输出行)显示一个列标题,其中n是一个正整数。 默认值是0,它显示列标题的第一行数据。 |
名称 | 简介 |
---|---|
S0 | 幸存者0空间利用率占空间当前容量的百分比。 |
S1 | 幸存者1空间利用率占空间当前容量的百分比。 |
E | Eden空间利用率占空间当前容量的百分比。 |
O | 旧空间利用率占空间当前容量的百分比。 |
M | Metaspace利用率占空间当前容量的百分比。 |
CCS | 压缩类空间利用率,以百分比表示。 |
YGC | 年轻一代GC事件的数量。 |
YGCT | 年轻一代的垃圾收集时间(S)。 |
FGC | 完整的GC事件的数量。 |
FGCT | 完整的垃圾收集时间(S)。 |
GCT | 垃圾收集总时间(S)。 |
名称 | 简介 |
---|---|
S0C | 当前幸存者空间0容量(kB)。 |
S1C | 当前幸存者空间1容量(kB)。 |
S0U | 幸存者空间0利用率(kB)。 |
S1U | 幸存者空间1利用率(kB)。 |
TT | 任期阀值 |
MTT | 最大任期阀值 |
DSS | 所需的幸存者大小(kB)。 |
EC | 当前eden空间容量(kB)。 |
EU | Eden空间利用率(kB)。 |
YGC | 年轻一代GC事件的数量。 |
YGCT | 年轻一代的垃圾收集时间(S)。 |
名称 | 简介 |
---|---|
OGCMN | 最小老年代容量(kB)。#从上图可以看出是670MB |
OGCMX | 最大老年代容量(kB)。#从上如可以看出最大内存是2730MB |
OGC | 当前的老年代容量(kB)。 #当前老年代是2730MB |
OC | 老年代大小(kB)。 |
YGC | 年轻一代GC事件的数量。 |
FGC | full GC事件的数量。 |
FGCT | 完整的垃圾收集时间(S)。 |
GCT | 垃圾收集总时间(S)。 |
名称 | 简介 |
---|---|
Loaded | 加载class的数量 |
Bytes | class字节大小 |
Unloaded | 卸载的类数。 |
Bytes | 卸载的千字节数。 |
Time | 执行类加载和卸载操作的时间。 |
名称 | 简介 |
---|---|
Compiled | 执行的编译任务数。 |
Failed | 编译任务的失败数量。 |
Invalid | 无效的编译任务数。 |
Time | 执行编译任务的时间。 |
FailedType | 编译最后一次失败编译的类型。 |
FailedMethod | 上次失败编译的类名称和方法。 |
名称 | 简介 |
---|---|
S0C | 当前survivor0区容量(kB)。 #大概是136MB |
S1C | 当前survivor1区容量(kB)。 #大概是136MB |
S0U | survivor0区已使用的容量(KB) #当前使用了17MB |
S1U | survivor1区已使用的容量(KB) |
EC | Eden区的总容量(KB) #Eden区的大小现在是1092MB |
EU | 当前Eden区已使用的容量(KB) #当前Eden区使用了1006MB |
OC | Old空间容量(kB)。 #当前老年代是2730MB |
OU | Old区已使用的容量(KB) #当前使用了748MB |
MC | Metaspace空间容量(KB) #在jdk1.7的版本MC是PC,也就是256MB |
MU | Metacspace使用量(KB) #也就是jdk1.7版本永久代使用了140MB |
CCSC | 压缩类空间容量(kB)。 |
CCSU | 压缩类空间使用(kB)。 |
YGC | 新生代垃圾回收次数 |
YGCT | 新生代垃圾回收时间 |
FGC | 老年代 full GC垃圾回收次数 |
FGCT | 老年代垃圾回收时间 |
GCT | 垃圾回收总消耗时间 |
名称 | 简介 |
---|---|
NGCMN | 年轻代(young)中初始化(最小)的大小(KB) |
NGCMX | 年轻代(young)的最大容量 (KB) |
NGC | 年轻代(young)中当前的容量 (KB) |
S0C | 年轻代中第一个survivor(幸存区)的容量 (KB) |
S1C | 年轻代中第二个survivor(幸存区)的容量 (KB) |
EC | 年轻代中Eden(伊甸园)的容量 (KB) |
OGCMN | old代中初始化(最小)的大小 (KB) |
OGCMX | old代的最大容量(KB) |
OGC | old代当前新生成的容量 (KB) |
OC | Old代的容量 (KB) |
PGCMN | perm代中初始化(最小)的大小 (KB) ,jdk1.8改为了MCMN |
PGCMX | perm代的最大容量 (KB),jdk1.8改为了MCMX |
PGC | perm代当前新生成的容量 (KB) |
PC | Perm(持久代)的容量 (KB) |
YGC | 从应用程序启动到采样时年轻代中gc次数 |
FGC | 从应用程序启动到采样时old代(全gc)gc次数 |
MC | Metaspace空间(KB) |
CCSMN | 压缩类空间最小容量(kB)。 |
CCSMX | 压缩类空间最大容量(kB)。 |
CCSC | 压缩类空间容量(kB)。 |
名称 | 简介 |
---|---|
NGCMN | 年轻代(young)中初始化(最小)的大小(kb) |
NGCMX | 年轻代(young)的最大容量 (kb) |
NGC | 年轻代(young)中当前的容量 (kb) |
S0CMX | 年轻代中第一个survivor(幸存区)的最大容量 (kb) |
S0C | 年轻代中第一个survivor(幸存区)的容量 (kb) |
S1CMX | 年轻代中第二个survivor(幸存区)的最大容量 (kb) |
S1C | 年轻代中第二个survivor(幸存区)的容量 (kb) |
ECMX | 年轻代中Eden(伊甸园)的最大容量 (kb) |
EC | 年轻代中Eden(伊甸园)的容量 (kb) |
YGC | 从应用程序启动到采样时年轻代中gc次数 |
FGC | 从应用程序启动到采样时old代(全gc)gc次数 |
名称 | 简介 |
---|---|
PC | Perm(持久代)的容量 (kb) #jdk1.8是MC Metaspace容量 |
PU | Perm(持久代)目前已使用空间 (kb) #jdk1.8是MU Metaspace目前的使用量 |
OC | Old代的容量 (kb) |
OU | Old代目前已使用空间 (kb) |
YGC | 从应用程序启动到采样时年轻代中gc次数 |
FGC | 从应用程序启动到采样时old代(全gc)gc次数 |
FGCT | 从应用程序启动到采样时old代(full gc)gc所用时间 |
GCT | 垃圾收集总时间 |
名称 | 简介 |
---|---|
OGCMN | old代中初始化(最小)的大小 (kb) |
OGCMX | old代的最大容量(kb) |
OGC | old代当前的容量 (kb) |
OC | Old代的容量 (kb) |
YGC | 从应用程序启动到采样时年轻代中gc次数 |
FGC | 从应用程序启动到采样时old代(全gc)gc次数 |
FGCT | 从应用程序启动到采样时old代(full gc)gc所用时间 |
GCT | 垃圾收集总时间。 |
文章字数:564,阅读全文大约需要2分钟
记一次查找问题的过程
做一个用jpa
从数据库中查找数据,修改再保存到数据库的简单功能。
查找出来后使用BeanUtil
将修改的信息放入jpa
的对象中,结果报了错误Could not copy property 'id' from source to target
查看BeanUtil
的源代码
1 | if (readMethod != null && ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) { |
发现在反射调用失败后统一返回这个异常,于是打断点。果然是反射报的异常。
检查属性是否一一对应,是否有公共的get
和set
,是否有基础类型(有的话传入空会空指针)
都没发现有问题,于是手动赋值又运行了一遍。
1 | a.setId(b.getId()); |
期初只是为了测试一下方法是否被私有化,属性名是否一致。结果抛出异常LazyInitializationException
这才是导致反射出错的原因,异常信息的意思大致是session
被关闭。在stackoverflow
上找到解决方法:方法上加上@Transactional
。
最后成功解决问题,回想了一下。当元素或者元素的lazy属性为true时执行find()
得到的只是一个代理对象,只有执行getId()
时才会从数据库中取。然后取的时候事务已经关闭了。(可能是因为find操作是在Stream流中进行的,流关闭事务也关闭了)加上@Transactional
注解可以使代码块事务统一。
文章字数:569,阅读全文大约需要2分钟
Keytool
是一个Java数据证书的管理工具。
Keytool
将秘钥(key
)和证书(certificates
)存在名为keystore
的文件中。keystore
中有两种数据key entity
),私钥+公钥trusted certificate entries
),公钥alias
别名,不区分大小写。keystore下又若干别名条目-genkey
: 在用户主目录中创建一个默认文件.keystore
,还会产生一个mykey
的别名,mykey
中包含用户的公钥、私钥和证书。没有指定目录,会生成在默认目录下。-alias
: 产生别名-keystore
: 指定秘钥库的名称。加上此命令,生成的各类信息将不在.keystore
文件中-keyalg
: 指定秘钥的算法,默认DSA
,可以设置成RSA
-validity
: 创建的证书有效期是多少天-keysize
: 指定秘钥长度-storepass
: 指定秘钥库的访问密码(查看秘钥库内容需要)-keypass
: 指定别名条目的密码(私钥的密码)-dname
: 指定证书拥有者的信息CN=名字与姓氏,OU=组织单位名称,O=组织名称,L=城市或区域名称,ST=州或省份名称,C=单位的两字母国家代码
-list
: 显示密钥库中的证书信息,例如keytool -list -v -keystore
, -storepass
指定密码-v
: 显示秘钥库中的证书详细信息-export
: 将别名指定的证书导出到文件,-alias
指定导出的别名,-keystore
指定keystore,-file
指定导出证书的位置及证书名称,-storepass
密码-file
: 指定导出文件的文件名-delete
: 删除秘钥库中某条目,keytool -delete -alias
指定删除的别名-printcert
: 查看导出的证书信息keytool -printcert -file xxx.crt
查看导出的证书信息-keypasswd
: 修改秘钥库中指定条目口令,-keypasswd -alias
指定需要修改的别名,-keypass 旧密码 -new 新密码 -storepass keystore密码 -keystore xxx
-storepasswd
: 修改keystore
口令,-storepasswd -keystore e:\sture.keystore(需修改口令的keystore) -storepass 123456(原始密码) -new 321(新密码)
-import
: 将签名数字证书导入秘钥库keytool -import -alias
指定导入条目的别名 -keystore
,-file
指定导入的证书生成keystore
keytool -genkey -v -alias broker -keyalg RSA -keystore broker.keystore -storepass brokerPwd -keypass brokerKeyPwd
查看keystore
keytool -list -v -keystore broker.keystore
keystore
导出成证书keytool -export -alias broker -keystore broker.keystore -file borker_cert -storepass brokerPwd
导入证书到truststore
keytool -import -v -file borker_cert -keystore client.truststore -storepass clientTrustPwd
jks
转p12
keytool -importkeystore -srckeystore keyStore.jks -srcstoretype JKS -deststoretype PKCS12 -destkeystore keyStore.p12
文章字数:546,阅读全文大约需要2分钟
QOS
即Quality of Service
服务质量,有发布者的QOS
和订阅者的QOS
level0
: 最多传输一次level1
: 至少传输一次level2
: 只有一次的传输1 | 生产者---》中间件---》消费者 |
只会发送一次,不管有没有收到。适合不是很重要的数据,比如传感器温度。反正很快会有下一次的数据。
1 | 生产者《------》中间件《-------》消费者 |
接受者需要发送确认信息,确认自己收到了。发送者如果没有收到确认信息就会再次发送。这个保证了发送的信息一定会到达,但是如果确认的信息没有被收到,可能导致重复发送。
1 | 发送者发送信息+信息编号--》接受者接收,保存编号--》确认收到+信息编号 |
增加了信息编号的传递,可以有效防止重复信息,但是多了删除编号的步骤。
并且假如接受者的删除请求没有到达(即没收到删除请求就有新的message)还会多次发送删除请求。
信息发送的次数过多。